Migrate to use new user fields

This commit is contained in:
Wil Clouser 2010-08-04 13:49:44 -07:00
Родитель 69c8f35a88
Коммит d96b6ceaa7
41 изменённых файлов: 298 добавлений и 214 удалений

Просмотреть файл

@ -4,6 +4,7 @@
"model": "users.userprofile",
"fields": {
"nickname": "fligtard",
"username": "fligtard",
"firstname": "Scott",
"lastname": "Bakula",
"email": "scott@bakula.com",
@ -29,6 +30,7 @@
"model": "users.userprofile",
"fields": {
"nickname": "milos",
"username": "milos",
"firstname": "Milos",
"lastname": "Dinic",
"email": "milos@dinic.com",
@ -66,4 +68,4 @@
}
}
]
]

Просмотреть файл

@ -285,6 +285,8 @@
"user": 55021,
"password": "",
"nickname": "55021",
"username": "55021",
"display_name": "55021",
"resetcode_expires": null,
"resetcode": "",
"created": "2007-03-05 13:09:56",

Просмотреть файл

@ -132,6 +132,8 @@
"user": 8735,
"password": "",
"nickname": "8735",
"username": "8735",
"display_name": "8735",
"resetcode_expires": null,
"resetcode": "",
"created": "2007-03-05 13:09:37",

Просмотреть файл

@ -174,6 +174,8 @@
"user": null,
"password": "",
"nickname": "41",
"username": "41",
"display_name": "41",
"resetcode_expires": null,
"resetcode": "",
"created": "2007-03-05 13:09:33",

Просмотреть файл

@ -229,6 +229,8 @@
"user": 10482,
"password": "",
"nickname": "clouserw",
"username": "clouserw",
"display_name": "clouserw",
"resetcode_expires": null,
"resetcode": "",
"created": "2007-03-05 13:09:38",

Просмотреть файл

@ -271,6 +271,8 @@
"user": 2519,
"password": "",
"nickname": "cfinke",
"username": "cfinke",
"display_name": "cfinke",
"resetcode_expires": null,
"resetcode": "",
"notes": null,

Просмотреть файл

@ -266,6 +266,8 @@
"user": 60582,
"password": "",
"nickname": "60582",
"username": "60582",
"display_name": "60582",
"resetcode_expires": null,
"resetcode": "",
"notes": null,

Просмотреть файл

@ -238,6 +238,8 @@
"user": 55021,
"password": "",
"nickname": "55021",
"username": "55021",
"display_name": "55021",
"resetcode_expires": null,
"resetcode": "",
"created": "2007-03-05 13:09:56",

Просмотреть файл

@ -249,6 +249,8 @@
"user": 9873,
"password": "",
"nickname": "9873",
"username": "9873",
"display_name": "9873",
"resetcode_expires": null,
"resetcode": "",
"created": "2007-03-05 13:09:37",

Просмотреть файл

@ -268,6 +268,8 @@
"user": null,
"password": "",
"nickname": "802",
"username": "802",
"display_name": "802",
"resetcode_expires": null,
"resetcode": "",
"created": "2007-03-05 13:09:33",

Просмотреть файл

@ -186,6 +186,8 @@
"user": null,
"password": "",
"nickname": "softcup",
"username": "softcup",
"display_name": "softcup",
"resetcode_expires": null,
"resetcode": "",
"created": "2007-03-05 13:09:37",

Просмотреть файл

@ -184,6 +184,8 @@
"user": null,
"password": "",
"nickname": "Aronnax",
"username": "Aronnax",
"display_name": "Aronnax",
"resetcode_expires": null,
"resetcode": "",
"created": "2007-03-05 13:09:33",

Просмотреть файл

@ -129,6 +129,8 @@
"user": null,
"password": "yermom",
"nickname": "Wink-RU",
"username": "Wink-RU",
"display_name": "Wink-RU",
"resetcode": "",
"created": "2008-08-29 06:53:46",
"modified": "2009-09-26 21:25:10",

Просмотреть файл

@ -40,6 +40,7 @@
"user": 4043307,
"password": "sha512$7b5436061f8c0902088c292c057be69fdb17312e2f71607c9c51641f5d876522$08d1d370d89e2ae92755fd03464a7276ca607c431d04a52d659f7a184f3f9918073637d82fc88981c7099c7c46a1137b9fdeb675304eb98801038905a9ee0600",
"nickname": "jbalogh",
"username": "jbalogh",
"resetcode_expires": "2010-01-12 15:28:07",
"resetcode": "",
"created": "2009-02-02 11:50:31",

Просмотреть файл

@ -40,6 +40,8 @@
"user": 2519,
"password": "",
"nickname": "cfinke",
"username": "cfinke",
"display_name": "cfinke",
"resetcode_expires": null,
"resetcode": "",
"created": "2007-03-05 13:09:34",

Просмотреть файл

@ -40,6 +40,8 @@
"user": 4043307,
"password": "",
"nickname": "jbalogh",
"username": "jbalogh",
"display_name": "jbalogh",
"resetcode_expires": null,
"resetcode": "",
"created": "2009-02-02 11:50:31",

Просмотреть файл

@ -19,6 +19,8 @@
"emailhidden": 0,
"password": "sha512$7b5436061f8c0902088c292c057be69fdb17312e2f71607c9c51641f5d876522$08d1d370d89e2ae92755fd03464a7276ca607c431d04a52d659f7a184f3f9918073637d82fc88981c7099c7c46a1137b9fdeb675304eb98801038905a9ee0600",
"nickname": "regularuser",
"username": "regularuser",
"display_name": "regularuser",
"resetcode_expires": "2010-01-12 15:28:07",
"resetcode": "",
"created": "2009-02-02 11:50:31",
@ -70,6 +72,8 @@
"user": 10482,
"password": "sha1$a04e0$0512298efb3e6e7dbace3976474151d396078fdd",
"nickname": "clouserw",
"username": "clouserw",
"display_name": "clouserw",
"resetcode_expires": "2010-01-01 00:00:00",
"resetcode": "",
"created": "2007-03-05 13:09:38",
@ -117,6 +121,8 @@
"user": 4043307,
"password": "sha512$7b5436061f8c0902088c292c057be69fdb17312e2f71607c9c51641f5d876522$08d1d370d89e2ae92755fd03464a7276ca607c431d04a52d659f7a184f3f9918073637d82fc88981c7099c7c46a1137b9fdeb675304eb98801038905a9ee0600",
"nickname": "admin",
"username": "admin",
"display_name": "admin",
"resetcode_expires": "2010-01-12 15:28:07",
"resetcode": "",
"created": "2009-02-02 11:50:31",

Просмотреть файл

@ -11,7 +11,7 @@ from django.core import paginator
from django.core.serializers import json
from django.core.mail import send_mail as django_send_mail
from django.utils.functional import Promise
from django.utils.encoding import smart_str
from django.utils.encoding import smart_str, smart_unicode
import pytz
@ -201,5 +201,5 @@ slug_re = re.compile('[^\w\s-]', re.UNICODE)
def slugify(s):
s = slug_re.sub('', unicode(s)).strip().lower()
s = slug_re.sub('', smart_unicode(s)).strip().lower()
return re.sub('[-\s]+', '-', s)

Просмотреть файл

@ -4,6 +4,7 @@
"model": "users.userprofile",
"fields": {
"nickname": "fligtard",
"username": "fligtard",
"firstname": "Scott",
"lastname": "Bakula",
"emailhidden": 1,

Просмотреть файл

@ -64,6 +64,7 @@
"user": 5293223,
"password": "sha512$7b5436061f8c0902088c292c057be69fdb17312e2f71607c9c51641f5d876522$08d1d370d89e2ae92755fd03464a7276ca607c431d04a52d659f7a184f3f9918073637d82fc88981c7099c7c46a1137b9fdeb675304eb98801038905a9ee0600",
"nickname": "root_x",
"username": "root_x",
"resetcode_expires": null,
"resetcode": "",
"created": "2010-04-21 12:29:12",
@ -147,6 +148,7 @@
"user": 346,
"password": "sha512$7b5436061f8c0902088c292c057be69fdb17312e2f71607c9c51641f5d876522$08d1d370d89e2ae92755fd03464a7276ca607c431d04a52d659f7a184f3f9918073637d82fc88981c7099c7c46a1137b9fdeb675304eb98801038905a9ee0600",
"nickname": "Wladimir Palant",
"username": "Wladimir Palant",
"resetcode_expires": null,
"resetcode": "",
"created": "2007-03-05 13:09:33",

Просмотреть файл

@ -41,6 +41,7 @@
"lastname": "",
"modified": "2009-10-19 06:21:02",
"nickname": "nobody",
"username": "nobody",
"email": "nobody@mozilla.org"
}
},

Просмотреть файл

@ -125,6 +125,7 @@
"bio": null,
"password": "sha512$280a921ec6e735ec6a1a76dc8802f3f6aee254f3fd71589010fe85ebce185f7a$c797ddde00731d7660b9e0c887d77b373e782eaa949e6101f17ada9a7236c426db53ac4344c133cdf32e73381bb7c7280efe5fdc5dd6134bbd2f706d994f94ff",
"nickname": "Join2",
"username": "Join2",
"resetcode_expires": null,
"resetcode": "",
"created": "2009-05-16 05:29:58",

Просмотреть файл

@ -16,6 +16,7 @@
"model": "users.userprofile",
"fields": {
"nickname": "jbalogh",
"username": "jbalogh",
"deleted": 0,
"user": 4043307,
"password": "sha512$7b5436061f8c0902088c292c057be69fdb17312e2f71607c9c51641f5d876522$08d1d370d89e2ae92755fd03464a7276ca607c431d04a52d659f7a184f3f9918073637d82fc88981c7099c7c46a1137b9fdeb675304eb98801038905a9ee0600",
@ -39,6 +40,7 @@
"model": "users.userprofile",
"fields": {
"nickname": "nobodyspecial",
"username": "nobodyspecial",
"deleted": 0,
"user": 8675309,
"password": "sha512$7b5436061f8c0902088c292c057be69fdb17312e2f71607c9c51641f5d876522$08d1d370d89e2ae92755fd03464a7276ca607c431d04a52d659f7a184f3f9918073637d82fc88981c7099c7c46a1137b9fdeb675304eb98801038905a9ee0600",

Просмотреть файл

@ -5,7 +5,7 @@ from django.utils.encoding import smart_unicode
import jingo
from access.admin import GroupUserInline
from .models import UserProfile, BlacklistedNickname
from .models import UserProfile, BlacklistedUsername
from .users import forms
@ -18,9 +18,8 @@ class UserAdmin(admin.ModelAdmin):
# XXX TODO: Ability to change the password (use AdminPasswordChangeForm)
fieldsets = (
(None, {
'fields': ('nickname', 'firstname', 'lastname', 'email',
'password', 'bio', 'homepage', 'location',
'occupation',),
'fields': ('email', 'username', 'display_name', 'password',
'bio', 'homepage', 'location', 'occupation',),
}),
('Registration', {
'fields': ('confirmationcode', 'resetcode',
@ -37,43 +36,44 @@ class UserAdmin(admin.ModelAdmin):
)
class BlacklistedNicknameAdmin(admin.ModelAdmin):
list_display = search_fields = ('nickname',)
class BlacklistedUsernameAdmin(admin.ModelAdmin):
list_display = search_fields = ('username',)
def add_view(self, request, form_url='', extra_context=None):
"""Override the default admin add view for bulk add."""
form = forms.BlacklistedNicknameAddForm()
form = forms.BlacklistedUsernameAddForm()
if request.method == 'POST':
form = forms.BlacklistedNicknameAddForm(request.POST)
form = forms.BlacklistedUsernameAddForm(request.POST)
if form.is_valid():
inserted = 0
duplicates = 0
for n in form.cleaned_data['nicknames'].splitlines():
for n in form.cleaned_data['usernames'].splitlines():
# check with teh cache
if BlacklistedNickname.blocked(n):
if BlacklistedUsername.blocked(n):
duplicates += 1
continue
n = smart_unicode(n).lower().encode('utf-8')
try:
BlacklistedNickname.objects.create(nickname=n)
BlacklistedUsername.objects.create(username=n)
inserted += 1
except IntegrityError:
# although unlikely, someone else could have added
# the nickname.
# the username.
# note: unless we manage the transactions manually,
# we do lose a primary id here
duplicates += 1
msg = '%s new nicknames added to the blacklist.' % (inserted)
msg = '%s new usernames added to the blacklist.' % (inserted)
if duplicates:
msg += ' %s duplicates were ignored.' % (duplicates)
messages.success(request, msg)
form = forms.BlacklistedNicknameAddForm()
form = forms.BlacklistedUsernameAddForm()
# Default django admin change list view does not print messages
# no redirect for now
# return http.HttpResponseRedirect(reverse(
# 'admin:users_blacklistednickname_changelist'))
return jingo.render(request, 'admin/blacklisted_nickname/add.html',
# 'admin:users_blacklistedusername_changelist'))
return jingo.render(request, 'admin/blacklisted_username/add.html',
{'form': form})
admin.site.register(UserProfile, UserAdmin)
admin.site.register(BlacklistedNickname, BlacklistedNicknameAdmin)
admin.site.register(BlacklistedUsername, BlacklistedUsernameAdmin)

Просмотреть файл

@ -40,6 +40,8 @@
"user": 4043307,
"password": "sha512$32e15df727a054aa56cf69accc142d1573372641a176aab9b0f1458e27dc6f3b$5bd3bd7811569776a07fbbb5e50156aa6ebdd0bec9267249b57da065340f0324190f1ad0d5f609dca19179a86c64807e22f789d118e6f7109c95b9c64ae8f619",
"nickname": "jbalogh",
"username": "jbalogh",
"display_name": "Jeff Balogh",
"resetcode_expires": "2010-01-12 15:28:07",
"resetcode": "",
"created": "2009-02-02 11:50:31",
@ -89,6 +91,8 @@
"user": null,
"password": "sha512$32e15df727a054aa56cf69accc142d1573372641a176aab9b0f1458e27dc6f3b$5bd3bd7811569776a07fbbb5e50156aa6ebdd0bec9267249b57da065340f0324190f1ad0d5f609dca19179a86c64807e22f789d118e6f7109c95b9c64ae8f619",
"nickname": "fligtar",
"username": "fligtar",
"display_name": "Justin Scott",
"resetcode_expires": "2010-01-12 15:28:07",
"resetcode": "",
"created": "2007-03-05 13:09:37",
@ -138,6 +142,8 @@
"user": 5349055,
"password": "sha512$9ec347fc67fc17c99a9dd43d1431a5959011acf247fb2128228c9a04208d1991$edcc677c7045ee2a379286e2ad6d99bd58af6b4a2117e1e4c2743923a9a297ce56d5311fe51baa4584c5483af0eaedc57700fbb4b719c0a84597c1609536ca4d",
"nickname": "barry",
"username": "barry",
"display_name": "barry",
"resetcode_expires": "2010-07-23 00:37:10",
"resetcode": "",
"created": "2010-07-03 23:03:11",
@ -148,9 +154,9 @@
},
{
"pk": 1,
"model": "users.blacklistednickname",
"model": "users.blacklistedusername",
"fields": {
"nickname": "ie6fan",
"username": "IE6Fan",
"modified": "2010-07-21 23:32:05",
"created": "2010-07-21 23:32:05"
}

Просмотреть файл

@ -7,7 +7,7 @@ from django.forms.util import ErrorList
import commonware.log
from tower import ugettext as _
from .models import UserProfile, BlacklistedNickname
from .models import UserProfile, BlacklistedUsername
log = commonware.log.getLogger('z.users')
@ -78,11 +78,11 @@ class UserRegisterForm(forms.ModelForm):
class Meta:
model = UserProfile
def clean_nickname(self):
"""We're breaking the rules and allowing null=True and blank=True on a
CharField because I want to enforce uniqueness in the db. In order to
let save() work, I override '' here."""
return self.cleaned_data['nickname'] or None
def clean_username(self):
name = self.cleaned_data['username']
if BlacklistedUsername.blocked(name):
raise forms.ValidationError("This username is invalid.")
return name
def clean(self):
super(UserRegisterForm, self).clean()
@ -98,26 +98,6 @@ class UserRegisterForm(forms.ModelForm):
self._errors["password2"] = ErrorList([msg])
del data["password2"]
# Names
if not ("nickname" in self._errors or
"firstname" in self._errors or
"lastname" in self._errors):
fname = data.get("firstname")
lname = data.get("lastname")
nname = data.get("nickname")
if not (fname or lname or nname):
msg = _("A first name, last name or nickname is required.")
self._errors["firstname"] = ErrorList([msg])
self._errors["lastname"] = ErrorList([msg])
self._errors["nickname"] = ErrorList([msg])
# Nickname could be blacklisted
if ("nickname" not in self._errors
and nname
and BlacklistedNickname.blocked(nname)):
msg = _("This nickname is invalid.")
self._errors["nickname"] = ErrorList([msg])
return data
@ -165,21 +145,21 @@ class UserEditForm(UserRegisterForm):
amouser.save()
class BlacklistedNicknameAddForm(forms.Form):
"""Form for adding blacklisted nickname in bulk fashion."""
nicknames = forms.CharField(widget=forms.Textarea(
class BlacklistedUsernameAddForm(forms.Form):
"""Form for adding blacklisted username in bulk fashion."""
usernames = forms.CharField(widget=forms.Textarea(
attrs={'cols': 40, 'rows': 16}))
def clean(self):
super(BlacklistedNicknameAddForm, self).clean()
super(BlacklistedUsernameAddForm, self).clean()
data = self.cleaned_data
if 'nicknames' in data:
data['nicknames'] = os.linesep.join(
[s.strip() for s in data['nicknames'].splitlines()
if 'usernames' in data:
data['usernames'] = os.linesep.join(
[s.strip() for s in data['usernames'].splitlines()
if s.strip()])
if 'nicknames' not in data or data['nicknames'] == '':
msg = 'Please enter at least one nickname to blacklist.'
self._errors['nicknames'] = ErrorList([msg])
if 'usernames' not in data or data['usernames'] == '':
msg = 'Please enter at least one username to blacklist.'
self._errors['usernames'] = ErrorList([msg])
return data

Просмотреть файл

@ -0,0 +1,27 @@
from django.core.management.base import BaseCommand
from django.db import connection
from celery.messaging import establish_connection
class Command(BaseCommand):
help = """A one time command to convert user fields. See
http://blog.mozilla.com/addons/2010/07/26/upcoming-changes-to-amo-accounts/
for details."""
def handle(self, *args, **options):
from users.tasks import add_usernames
from amo.utils import chunked
print "Getting users..."
cursor = connection.cursor()
# Doing this directly because I don't want to load 800k user objects
cursor.execute("SELECT id, firstname, lastname, nickname FROM users")
data = cursor.fetchall()
with establish_connection() as conn:
for chunk in chunked(data, 400):
print "Sending data to celeryd..."
add_usernames.apply_async(args=[chunk], connection=conn)
print "All done."

Просмотреть файл

@ -47,10 +47,16 @@ class UserManager(amo.models.ManagerBase):
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)
nickname = models.CharField(max_length=255, default='', null=True,
blank=True)
firstname = models.CharField(max_length=255, default='', null=True, blank=True)
lastname = models.CharField(max_length=255, default='', null=True, blank=True)
username = models.CharField(max_length=255, default='', unique=True)
display_name = models.CharField(max_length=255, default='', null=True,
blank=True)
password = models.CharField(max_length=255, default='')
email = models.EmailField(unique=True)
@ -83,7 +89,7 @@ class UserProfile(amo.models.ModelBase):
db_table = 'users'
def __unicode__(self):
return '%s: %s' % (self.id, self.display_name)
return '%s: %s' % (self.id, self.display_name or self.username)
def get_url_path(self):
return reverse('users.profile', args=[self.id])
@ -98,12 +104,6 @@ class UserProfile(amo.models.ModelBase):
"""Public add-ons this user is listed as author of."""
return self.addons.valid().filter(addonuser__listed=True).distinct()
@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))
@ -119,23 +119,9 @@ class UserProfile(amo.models.ModelBase):
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 ''
return self.display_name or self.username
@amo.cached_property
def reviews(self):
@ -149,6 +135,8 @@ class UserProfile(amo.models.ModelBase):
self.firstname = ""
self.lastname = ""
self.nickname = None
self.username = "Anonymous-%s" % self.id # Can't be null
self.display_name = None
self.homepage = ""
self.deleted = True
self.picture_type = ""
@ -194,9 +182,9 @@ class UserProfile(amo.models.ModelBase):
# 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.first_name = ''
self.user.last_name = ''
self.user.username = self.email # f
self.user.email = self.email
self.user.password = self.password
self.user.date_joined = self.created
@ -236,21 +224,24 @@ class UserProfile(amo.models.ModelBase):
user.mobile_addons = qs.values_list('addon', flat=True)
class BlacklistedNickname(amo.models.ModelBase):
"""Blacklisted user nicknames."""
nickname = models.CharField(max_length=255, unique=True, default='')
class BlacklistedUsername(amo.models.ModelBase):
"""Blacklisted user usernames."""
username = models.CharField(max_length=255, unique=True, default='')
class Meta:
db_table = 'users_blacklistedusername'
def __unicode__(self):
return self.nickname
return self.username
@classmethod
def blocked(cls, nick):
"""Check to see if a nickname is in the (cached) blacklist."""
nick = smart_unicode(nick).lower()
def blocked(cls, username):
"""Check to see if a username is in the (cached) blacklist."""
username = smart_unicode(username).lower()
qs = cls.objects.all()
f = lambda: dict(qs.values_list('nickname', 'id'))
f = lambda: [u.lower() for u in qs.values_list('username', flat=True)]
blacklist = caching.cached_with(qs, f, 'blocked')
return nick in blacklist
return username in blacklist
class PersonaAuthor(unicode):

Просмотреть файл

@ -1,13 +1,55 @@
import random
from django.contrib.auth.models import User as DjangoUser
from django.db import IntegrityError
import commonware.log
from celery.decorators import task
from . import cron
from django.contrib.auth.models import User as DjangoUser
from amo.utils import slugify
from users.models import UserProfile
task_log = commonware.log.getLogger('z.task')
@task(rate_limit='20/m')
def add_usernames(data, **kw):
"""Temporary method. Roll me back in 5.11.9. See bug 582727."""
task_log.info("[%s@%s] Bulk touching users" %
(len(data), add_usernames.rate_limit))
def old_display_name(user):
if not user[3]:
return u'%s %s' % (user[1], user[2])
else:
return user[3]
for user in data:
name = old_display_name(user)
name_slug = slugify(name)
try:
UserProfile.objects.filter(id=user[0]).update(username=name_slug,
display_name=name)
except IntegrityError, e:
try:
name_slug = "%s%s" % (name_slug, user[0])
if not len(name_slug) > 10:
# This can happen if they have a blank name_slug and then
# there is already a username in the system that corresponds
# to their user id. It's a total edge case.
name_slug = "%s%s" % (random.randint(1000,100000),
name_slug)
UserProfile.objects.filter(id=user[0]).update(username=name_slug,
display_name=name)
except IntegrityError, e:
task_log.error(u"""F-F-Fail! I tried setting a user's (id:%s)
username to to %s and it was already taken. This should never
happen.""" % (user[0], name_slug))
@task(rate_limit='40/m')
def _delete_users(data, **kw):
"""Feed me a list of user ids you want to delete from the database. This

Просмотреть файл

@ -5,20 +5,20 @@
<link rel="stylesheet" href="{{ MEDIA_URL }}css/zamboni/admin-django.css">
{% endblock %}
{% block title %}{{ page_title('Add Blacklisted Nicknames') }}{% endblock %}
{% block title %}{{ page_title('Add Blacklisted Usernames') }}{% endblock %}
{% block bodyclass %}users-blacklistednickname change-form{% endblock %}
{% block bodyclass %}users-blacklistedusername change-form{% endblock %}
{% block content %}
<div class="breadcrumbs">
<a href="{{ url('admin:index') }}">Home</a> &rsaquo;
<a href="{{ url('admin:app_list', app_label='users') }}">Users</a> &rsaquo;
<a href="{{ url('admin:users_blacklistednickname_changelist') }}">Blacklisted nicknames</a> &rsaquo;
<a href="{{ url('admin:users_blacklistedusername_changelist') }}">Blacklisted usernames</a> &rsaquo;
Add
</div>
<div id="content" class="colM">
<h2>Add Blacklisted Nicknames</h2>
<h2>Add Blacklisted Usernames</h2>
<div id="content-main">
{% if messages %}
{% for message in messages %}
@ -31,11 +31,11 @@
{% if form %}
<form method="post" action="">
{{ csrf() }}
<p>Enter one nickname per line.</p>
<p>Enter one username per line.</p>
<div class="form-row">
{{ form.nicknames.errors|safe }}
<label for="id_nicknames">Blacklisted Nicknames {{ required() }}</label>
{{ form.nicknames|safe }}
{{ form.usernames.errors|safe }}
<label for="id_usernames">Blacklisted Usernames {{ required() }}</label>
{{ form.usernames|safe }}
</div>
<div class="submit-row">
<input type="submit" name="_save" class="default" value="Save">

Просмотреть файл

@ -29,9 +29,9 @@
<legend>{{ _('My account') }}</legend>
<ul>
<li>
<label for="id_nickname">{{ _('Nickname') }} {{ required() }}</label>
{{ form.nickname|safe }}
{{ form.nickname.errors|safe }}
<label for="id_username">{{ _('Username') }} {{ required() }}</label>
{{ form.username|safe }}
{{ form.username.errors|safe }}
</li>
<li>
<label for="id_email">{{ _('Email Address') }} {{ required() }}</label>
@ -106,14 +106,9 @@
<legend>{{ _('Profile information') }}</legend>
<ol>
<li>
<label for="id_firstname">{{ _('First name') }} {{ required() }}</label>
{{ form.firstname|safe }}
{{ form.firstname.errors|safe }}
</li>
<li>
<label for="id_lastname">{{ _('Last name') }}</label>
{{ form.lastname|safe }}
{{ form.lastname.errors|safe }}
<label for="id_display_name">{{ _('Display Name') }}</label>
{{ form.display_name|safe }}
{{ form.display_name.errors|safe }}
</li>
<li>
<label for="id_location">{{ _('Location') }}</label>

Просмотреть файл

@ -22,19 +22,14 @@
<fieldset>
<ul>
<li>
<label for="id_firstname">{{ _('First name') }} {{ required() }}</label>
{{ form.firstname|safe }}
{{ form.firstname.errors|safe }}
<label for="id_username">{{ _('Username') }} {{ required() }}</label>
{{ form.username|safe }}
{{ form.username.errors|safe }}
</li>
<li>
<label for="id_lastname">{{ _('Last name') }}</label>
{{ form.lastname|safe }}
{{ form.lastname.errors|safe }}
</li>
<li>
<label for="id_nickname">{{ _('Nickname') }} {{ required() }}</label>
{{ form.nickname|safe }}
{{ form.nickname.errors|safe }}
<label for="id_display_name">{{ _('Display name') }}</label>
{{ form.display_name|safe }}
{{ form.display_name.errors|safe }}
</li>
<li>
<label for="id_homepage">{{ _('Homepage') }}</label>

Просмотреть файл

@ -2,10 +2,13 @@ from django import test
from django.contrib.auth import authenticate
from django.core.cache import cache
import test_utils
import amo.test_utils
from users.models import UserProfile
class TestAmoUserBackend(test.TestCase):
class TestAmoUserBackend(amo.test_utils.ExtraSetup, test_utils.TestCase):
fixtures = ['users/test_backends']
def setUp(self):

Просмотреть файл

@ -3,15 +3,16 @@ from django.contrib.auth.tokens import default_token_generator
from django.core import mail
from django.utils.http import int_to_base36
import test_utils
from manage import settings
from nose.tools import eq_
import test_utils
import amo.test_utils
from amo.helpers import urlparams
from amo.urlresolvers import reverse
class UserFormBase(test_utils.TestCase):
class UserFormBase(amo.test_utils.ExtraSetup, test_utils.TestCase):
fixtures = ['users/test_backends']
@ -110,22 +111,16 @@ class TestUserEditForm(UserFormBase):
def test_no_names(self):
self.client.login(username='jbalogh@mozilla.com', password='foo')
data = {'nickname': '',
'email': 'jbalogh@mozilla.com',
'firstname': '',
'lastname': '', }
data = {'username': '',
'email': 'jbalogh@mozilla.com', }
r = self.client.post('/en-US/firefox/users/edit', data)
msg = "A first name, last name or nickname is required."
self.assertFormError(r, 'form', 'nickname', msg)
self.assertFormError(r, 'form', 'firstname', msg)
self.assertFormError(r, 'form', 'lastname', msg)
msg = "This field is required."
self.assertFormError(r, 'form', 'username', msg)
def test_no_real_name(self):
self.client.login(username='jbalogh@mozilla.com', password='foo')
data = {'nickname': 'blah',
'email': 'jbalogh@mozilla.com',
'firstname': '',
'lastname': '', }
data = {'username': 'blah',
'email': 'jbalogh@mozilla.com', }
r = self.client.post('/en-US/firefox/users/edit', data, follow=True)
self.assertContains(r, "Profile Updated")
@ -151,7 +146,7 @@ class TestUserEditForm(UserFormBase):
def test_set_new_passwords(self):
self.client.login(username='jbalogh@mozilla.com', password='foo')
data = {'nickname': 'jbalogh',
data = {'username': 'jbalogh',
'email': 'jbalogh@mozilla.com',
'oldpassword': 'foo',
'password': 'new',
@ -181,13 +176,13 @@ class TestUserLoginForm(UserFormBase):
url = self._get_login_url()
r = self.client.post(url, {'username': 'jbalogh@mozilla.com',
'password': 'foo'}, follow=True)
self.assertContains(r, "Welcome, Jeff")
self.assertContains(r, "Welcome, Jeff Balogh")
self.assertTrue(self.client.session.get_expire_at_browser_close())
r = self.client.post(url, {'username': 'jbalogh@mozilla.com',
'password': 'foo',
'rememberme': 1}, follow=True)
self.assertContains(r, "Welcome, Jeff")
self.assertContains(r, "Welcome, Jeff Balogh")
# Subtract 100 to give some breathing room
age = settings.SESSION_COOKIE_AGE - 100
assert self.client.session.get_expiry_age() > age
@ -231,22 +226,17 @@ class TestUserRegisterForm(UserFormBase):
data = {'email': '',
'password': '',
'password2': '',
'firstname': '',
'lastname': '',
'nickname': '', }
'username': '', }
r = self.client.post('/en-US/firefox/users/register', data)
self.assertFormError(r, 'form', 'email',
'This field is required.')
msg = "A first name, last name or nickname is required."
self.assertFormError(r, 'form', 'nickname', msg)
self.assertFormError(r, 'form', 'firstname', msg)
self.assertFormError(r, 'form', 'lastname', msg)
msg = "This field is required."
self.assertFormError(r, 'form', 'email', msg)
self.assertFormError(r, 'form', 'username', msg)
def test_register_existing_account(self):
data = {'email': 'jbalogh@mozilla.com',
'password': 'xxx',
'password2': 'xxx',
'firstname': 'xxx', }
'username': 'xxx', }
r = self.client.post('/en-US/firefox/users/register', data)
self.assertFormError(r, 'form', 'email',
'User profile with this Email already exists.')
@ -261,14 +251,14 @@ class TestUserRegisterForm(UserFormBase):
'The passwords did not match.')
eq_(len(mail.outbox), 0)
def test_invalid_nickname(self):
def test_invalid_username(self):
data = {'email': 'testo@example.com',
'password': 'xxx',
'password2': 'xxx',
'nickname': 'IE6Fan', }
'username': 'IE6Fan', }
r = self.client.post('/en-US/firefox/users/register', data)
self.assertFormError(r, 'form', 'nickname',
'This nickname is invalid.')
self.assertFormError(r, 'form', 'username',
'This username is invalid.')
def test_already_logged_in(self):
self.client.login(username='jbalogh@mozilla.com', password='foo')
@ -280,9 +270,7 @@ class TestUserRegisterForm(UserFormBase):
data = {'email': 'john.connor@sky.net',
'password': 'carebears',
'password2': 'carebears',
'firstname': 'John',
'lastname': 'Connor',
'nickname': 'BigJC',
'username': 'BigJC',
'homepage': ''}
r = self.client.post('/en-US/firefox/users/register', data)
self.assertContains(r, "Congratulations!")
@ -296,22 +284,22 @@ class TestUserRegisterForm(UserFormBase):
(u.id, u.confirmationcode)) > 0
class TestBlacklistedNicknameAdminAddForm(UserFormBase):
class TestBlacklistedUsernameAdminAddForm(UserFormBase):
def test_no_nicknames(self):
def test_no_usernames(self):
self.client.login(username='testo@example.com', password='foo')
url = reverse('admin:users_blacklistednickname_add')
data = {'nicknames': "\n\n", }
url = reverse('admin:users_blacklistedusername_add')
data = {'usernames': "\n\n", }
r = self.client.post(url, data)
msg = 'Please enter at least one nickname to blacklist.'
self.assertFormError(r, 'form', 'nicknames', msg)
msg = 'Please enter at least one username to blacklist.'
self.assertFormError(r, 'form', 'usernames', msg)
def test_add(self):
self.client.login(username='testo@example.com', password='foo')
url = reverse('admin:users_blacklistednickname_add')
data = {'nicknames': "IE6Fan\nFubar\n\n fubar \n", }
url = reverse('admin:users_blacklistedusername_add')
data = {'usernames': "IE6Fan\nfubar\n\n", }
r = self.client.post(url, data)
msg = '1 new nicknames added to the blacklist. '
msg += '2 duplicates were ignored.'
msg = '1 new usernames added to the blacklist. '
msg += '1 duplicates were ignored.'
self.assertContains(r, msg)
self.assertNotContains(r, 'fubar')

Просмотреть файл

@ -22,7 +22,7 @@ def test_emaillink():
def test_user_link():
u = UserProfile(firstname='John', lastname='Connor', pk=1)
u = UserProfile(username='jconnor', display_name='John Connor', pk=1)
eq_(user_link(u), '<a href="%s">John Connor</a>' %
reverse('users.profile', args=[1]))
@ -31,8 +31,8 @@ def test_user_link():
def test_users_list():
u1 = UserProfile(firstname='John', lastname='Connor', pk=1)
u2 = UserProfile(firstname='Sarah', lastname='Connor', pk=2)
u1 = UserProfile(username='jconnor', display_name='John Connor', pk=1)
u2 = UserProfile(username='sconnor', display_name='Sarah Connor', pk=2)
eq_(users_list([u1, u2]), ', '.join((user_link(u1), user_link(u2))))
# handle None gracefully
@ -41,6 +41,6 @@ def test_users_list():
def test_user_link_unicode():
"""make sure helper won't choke on unicode input"""
u = UserProfile(firstname=u'Jürgen', lastname=u'Müller', pk=1)
u = UserProfile(username=u'jmüller', display_name=u'Jürgen Müller', pk=1)
eq_(user_link(u), u'<a href="%s">Jürgen Müller</a>' %
reverse('users.profile', args=[1]))

Просмотреть файл

@ -5,16 +5,17 @@ from django import test
from django.contrib.auth.models import User
from django.core import mail
import test_utils
from nose.tools import eq_
import amo.test_utils
from addons.models import Addon, AddonUser
from bandwagon.models import Collection
from reviews.models import Review
from users.models import UserProfile, get_hexdigest, BlacklistedNickname
from users.models import UserProfile, get_hexdigest, BlacklistedUsername
class TestUserProfile(amo.test_utils.ExtraSetup, test.TestCase):
class TestUserProfile(amo.test_utils.ExtraSetup, test_utils.TestCase):
fixtures = ('base/addon_3615', 'base/user_2519', 'users/test_backends',
'base/apps',)
@ -25,10 +26,6 @@ class TestUserProfile(amo.test_utils.ExtraSetup, test.TestCase):
x = User.objects.get(id='4043307').get_profile()
eq_(x.email, "")
def test_display_name_nickname(self):
u = UserProfile(nickname='Terminator', pk=1)
eq_(u.display_name, 'Terminator')
def test_email_confirmation_code(self):
u = User.objects.get(id='4043307').get_profile()
u.confirmationcode = 'blah'
@ -40,23 +37,15 @@ class TestUserProfile(amo.test_utils.ExtraSetup, test.TestCase):
(u.id, u.confirmationcode)) > 0
def test_welcome_name(self):
u1 = UserProfile(lastname='Connor')
u2 = UserProfile(firstname='Sarah', nickname='sc', lastname='Connor')
u3 = UserProfile(nickname='sc', lastname='Connor')
u4 = UserProfile()
eq_(u1.welcome_name, 'Connor')
eq_(u2.welcome_name, 'Sarah')
eq_(u3.welcome_name, 'sc')
eq_(u4.welcome_name, '')
u1 = UserProfile(username='sc')
u2 = UserProfile(username='sc', display_name="Sarah Connor")
u3 = UserProfile()
eq_(u1.welcome_name, 'sc')
eq_(u2.welcome_name, 'Sarah Connor')
eq_(u3.welcome_name, '')
def test_name(self):
u1 = UserProfile(firstname='Sarah', lastname='Connor')
u2 = UserProfile(firstname='Sarah')
eq_(u1.name, 'Sarah Connor')
eq_(u2.name, 'Sarah') # No trailing space
def test_empty_nickname(self):
u = UserProfile.objects.create(email='yoyoyo@yo.yo', nickname='yoyo')
def test_empty_username(self):
u = UserProfile.objects.create(email='yoyoyo@yo.yo', username='yoyo')
assert u.user is None
u.create_django_user()
eq_(u.user.username, 'yoyoyo@yo.yo')
@ -69,8 +58,8 @@ class TestUserProfile(amo.test_utils.ExtraSetup, test.TestCase):
as resetcode_expires as None
"""
u = UserProfile(lastname='Connor', pk=2, resetcode_expires=None,
nickname='jconnor', email='j.connor@sky.net')
u = UserProfile(username='jconnor', pk=2, resetcode_expires=None,
email='j.connor@sky.net')
u.save()
assert u.resetcode_expires
@ -136,7 +125,7 @@ class TestUserProfile(amo.test_utils.ExtraSetup, test.TestCase):
eq_(c.slug, 'favorites')
class TestPasswords(test.TestCase):
class TestPasswords(amo.test_utils.ExtraSetup, test_utils.TestCase):
def test_invalid_old_password(self):
u = UserProfile(password='sekrit')
@ -162,9 +151,9 @@ class TestPasswords(test.TestCase):
assert u.check_password('sekrit') is True
class TestBlacklistedNickname(test.TestCase):
class TestBlacklistedUsername(amo.test_utils.ExtraSetup, test_utils.TestCase):
fixtures = ['users/test_backends']
def test_blocked(self):
eq_(BlacklistedNickname.blocked('IE6Fan'), True)
eq_(BlacklistedNickname.blocked('testo'), False)
eq_(BlacklistedUsername.blocked('IE6Fan'), True)
eq_(BlacklistedUsername.blocked('testo'), False)

Просмотреть файл

@ -1,11 +1,14 @@
from django import test
import test_utils
from nose.tools import eq_
import amo.test_utils
from users.utils import EmailResetCode
class TestEmailResetCode(test.TestCase):
class TestEmailResetCode(amo.test_utils.ExtraSetup, test_utils.TestCase):
def test_parse(self):
id = 1

Просмотреть файл

@ -5,9 +5,10 @@ from django.core.cache import cache
from django.contrib.auth.models import User
from django.test.client import Client
from nose.tools import eq_
import test_utils
from nose.tools import eq_
import amo.test_utils
from access.models import Group, GroupUser
from amo.helpers import urlparams
from amo.pyquery_wrapper import PyQuery
@ -15,7 +16,7 @@ from amo.urlresolvers import reverse
from users.utils import EmailResetCode
class UserViewBase(test_utils.TestCase):
class UserViewBase(amo.test_utils.ExtraSetup, test_utils.TestCase):
fixtures = ['users/test_backends']
@ -47,17 +48,16 @@ class TestEdit(UserViewBase):
def test_email_change_mail_sent(self):
self.client.login(username='jbalogh@mozilla.com', password='foo')
data = {'nickname': 'jbalogh',
data = {'username': 'jbalogh',
'email': 'jbalogh.changed@mozilla.com',
'firstname': 'DJ SurfNTurf',
'lastname': 'Balogh', }
'display_name': 'DJ SurfNTurf', }
r = self.client.post('/en-US/firefox/users/edit', data, follow=True)
self.assertContains(r, "An email has been sent to %s" % data['email'])
# The email shouldn't change until they confirm, but the name should
u = User.objects.get(id='4043307').get_profile()
self.assertEquals(u.firstname, 'DJ SurfNTurf')
self.assertEquals(u.display_name, 'DJ SurfNTurf')
self.assertEquals(u.email, 'jbalogh@mozilla.com')
eq_(len(mail.outbox), 1)

Просмотреть файл

@ -33,7 +33,7 @@ def ajax(request):
"""Query for a user matching a given email."""
email = request.GET.get('q','').strip()
u = get_object_or_404(UserProfile, email=email)
return dict(id=u.id, name=u.name)
return dict(id=u.id, name=u.display_name)
def confirm(request, user_id, token):
@ -134,6 +134,7 @@ def edit(request):
form.save()
return http.HttpResponseRedirect(reverse('users.edit'))
else:
messages.error(request, _('There were errors in the changes '
'you made. Please correct them and '
'resubmit.'))
@ -313,7 +314,8 @@ def register(request):
u.emailhidden = data.get('emailhidden', False)
u.firstname = data.get('firstname', None)
u.lastname = data.get('lastname', None)
u.nickname = data.get('nickname', None)
u.username = data.get('username', None)
u.display_name = data.get('display_name', None)
u.homepage = data.get('homepage', None)
u.set_password(data.get('password'))

Просмотреть файл

@ -29,6 +29,7 @@
"lastname": "Villalobos",
"modified": "2009-09-22 09:12:24",
"nickname": "jorge.villalobos",
"username": "jorge.villalobos",
"email": "jorge@mozilla.com"
}
},
@ -238,6 +239,7 @@
"user": 4043307,
"password": "sha512$7b5436061f8c0902088c292c057be69fdb17312e2f71607c9c51641f5d876522$08d1d370d89e2ae92755fd03464a7276ca607c431d04a52d659f7a184f3f9918073637d82fc88981c7099c7c46a1137b9fdeb675304eb98801038905a9ee0600",
"nickname": "jbalogh",
"username": "jbalogh",
"resetcode_expires": "2010-01-12 15:28:07",
"resetcode": "",
"created": "2009-02-02 11:50:31",

Просмотреть файл

@ -0,0 +1,17 @@
RENAME TABLE `users_blacklistednickname` TO `users_blacklistedusername`;
ALTER TABLE `users_blacklistedusername` CHANGE `nickname` `username` varchar(255) NOT NULL default '';
ALTER TABLE `users_blacklistedusername` DROP KEY `nickname`;
ALTER TABLE `users_blacklistedusername` ADD UNIQUE(`username`);
-- Will take 1-3 minutes
ALTER TABLE `users`
ADD COLUMN `username` varchar(255) UNIQUE default NULL after `email`,
ADD COLUMN `display_name` varchar(255) default NULL after `username`;
-- This needs to be run after the convert_user_fields management command. Since
-- that's going in at the same time as this but has to be run manually, I'm
-- leaving this commented out.
-- Query OK, 859523 rows affected (2 min 24.52 sec)
-- ALTER TABLE users CHANGE COLUMN `username` `username` varchar(255) NOT NULL;