Commit 2b6bc762e81b07833bd963bb6f45fddf6873c8b0

Authored by Andrew Buss
1 parent 4401f6495c
Exists in master

expanded registration

Showing 6 changed files with 178 additions and 46 deletions Side-by-side Diff

flashcards/admin.py View file @ 2b6bc76
1 1 from django.contrib import admin
2 2 from flashcards.models import Flashcard, UserFlashcard, Section, FlashcardMask, \
3   - UserFlashcardReview
  3 + UserFlashcardReview, LecturePeriod, User
  4 +from simple_email_confirmation import EmailAddress
4 5  
5 6 admin.site.register([
  7 + User,
6 8 Flashcard,
7 9 FlashcardMask,
8 10 UserFlashcard,
9 11 UserFlashcardReview,
10   - Section
  12 + Section,
  13 + LecturePeriod
11 14 ])
flashcards/api.py View file @ 2b6bc76
  1 +from django.contrib.auth import login, authenticate
1 2 from django.core.mail import send_mail
2 3 from rest_framework.views import APIView
3 4 from rest_framework.response import Response
... ... @@ -41,8 +42,8 @@
41 42 raise ValidationError('Password is required')
42 43  
43 44 email = request.data['email']
44   - user = User.objects.create_user(email)
45   -
  45 + user = User.objects.create_user(email, email=email)
  46 + user.confirm_email(user.confirmation_key)
46 47 body = '''
47 48 Visit the following link to confirm your email address:
48 49 http://flashy.cards/app/verify_email/%s
... ... @@ -54,6 +55,9 @@
54 55 body % user.confirmation_key,
55 56 "noreply@flashy.cards",
56 57 [user.email])
  58 + user = authenticate(username=email, password=request.data['password'])
  59 + print user
  60 + login(request, user)
57 61  
58 62 return Response(UserSerializer(User).data)
flashcards/migrations/0001_initial.py View file @ 2b6bc76
  1 +# -*- coding: utf-8 -*-
  2 +from __future__ import unicode_literals
  3 +
  4 +from django.db import models, migrations
  5 +import django.contrib.auth.models
  6 +import django.utils.timezone
  7 +from django.conf import settings
  8 +import django.core.validators
  9 +import simple_email_confirmation.models
  10 +
  11 +
  12 +class Migration(migrations.Migration):
  13 +
  14 + dependencies = [
  15 + ('auth', '0007_customuser_extensionuser'),
  16 + ]
  17 +
  18 + operations = [
  19 + migrations.CreateModel(
  20 + name='User',
  21 + fields=[
  22 + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
  23 + ('password', models.CharField(max_length=128, verbose_name='password')),
  24 + ('last_login', models.DateTimeField(null=True, verbose_name='last login', blank=True)),
  25 + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
  26 + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, max_length=30, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.', 'invalid')], help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True, verbose_name='username')),
  27 + ('first_name', models.CharField(max_length=30, verbose_name='first name', blank=True)),
  28 + ('last_name', models.CharField(max_length=30, verbose_name='last name', blank=True)),
  29 + ('email', models.EmailField(max_length=254, verbose_name='email address', blank=True)),
  30 + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
  31 + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
  32 + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
  33 + ('groups', models.ManyToManyField(related_query_name='user', related_name='user_set', to='auth.Group', blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', verbose_name='groups')),
  34 + ],
  35 + options={
  36 + 'abstract': False,
  37 + 'verbose_name': 'user',
  38 + 'verbose_name_plural': 'users',
  39 + },
  40 + bases=(models.Model, simple_email_confirmation.models.SimpleEmailConfirmationUserMixin),
  41 + managers=[
  42 + (b'objects', django.contrib.auth.models.UserManager()),
  43 + ],
  44 + ),
  45 + migrations.CreateModel(
  46 + name='Flashcard',
  47 + fields=[
  48 + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
  49 + ('text', models.CharField(help_text=b'The text on the card', max_length=255)),
  50 + ('pushed', models.DateTimeField(help_text=b'When the card was first pushed', auto_now_add=True)),
  51 + ('material_date', models.DateTimeField(help_text=b'The date with which the card is associated')),
  52 + ('is_hidden', models.BooleanField(default=False)),
  53 + ('hide_reason', models.CharField(help_text=b'Reason for hiding this card', max_length=255, blank=True)),
  54 + ('author', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
  55 + ],
  56 + options={
  57 + 'ordering': ['-pushed'],
  58 + },
  59 + ),
  60 + migrations.CreateModel(
  61 + name='FlashcardMask',
  62 + fields=[
  63 + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
  64 + ('ranges', models.CharField(max_length=255)),
  65 + ],
  66 + ),
  67 + migrations.CreateModel(
  68 + name='LecturePeriod',
  69 + fields=[
  70 + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
  71 + ('week_day', models.IntegerField(help_text=b'0-indexed day of week, starting at Monday')),
  72 + ('start_time', models.TimeField()),
  73 + ('end_time', models.TimeField()),
  74 + ],
  75 + ),
  76 + migrations.CreateModel(
  77 + name='Section',
  78 + fields=[
  79 + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
  80 + ('department', models.CharField(max_length=50)),
  81 + ('course_num', models.CharField(max_length=6)),
  82 + ('course_title', models.CharField(max_length=50)),
  83 + ('instructor', models.CharField(max_length=50)),
  84 + ('quarter', models.CharField(max_length=4)),
  85 + ],
  86 + options={
  87 + 'ordering': ['-quarter'],
  88 + },
  89 + ),
  90 + migrations.CreateModel(
  91 + name='UserFlashcard',
  92 + fields=[
  93 + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
  94 + ('pulled', models.DateTimeField(help_text=b'When the user pulled the card', null=True, blank=True)),
  95 + ('unpulled', models.DateTimeField(help_text=b'When the user unpulled this card', null=True, blank=True)),
  96 + ('flashcard', models.ForeignKey(to='flashcards.Flashcard')),
  97 + ('mask', models.ForeignKey(help_text=b"A mask which overrides the card's mask", to='flashcards.FlashcardMask')),
  98 + ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
  99 + ],
  100 + options={
  101 + 'ordering': ['-pulled'],
  102 + },
  103 + ),
  104 + migrations.CreateModel(
  105 + name='UserFlashcardReview',
  106 + fields=[
  107 + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
  108 + ('when', models.DateTimeField()),
  109 + ('blanked_word', models.CharField(help_text=b'The character range which was blanked', max_length=8, blank=True)),
  110 + ('response', models.CharField(help_text=b"The user's response", max_length=255, null=True, blank=True)),
  111 + ('correct', models.NullBooleanField(help_text=b"The user's self-evaluation of their response")),
  112 + ('user_flashcard', models.ForeignKey(to='flashcards.UserFlashcard')),
  113 + ],
  114 + ),
  115 + migrations.AlterUniqueTogether(
  116 + name='section',
  117 + unique_together=set([('department', 'course_num', 'quarter', 'instructor')]),
  118 + ),
  119 + migrations.AddField(
  120 + model_name='lectureperiod',
  121 + name='section',
  122 + field=models.ForeignKey(to='flashcards.Section'),
  123 + ),
  124 + migrations.AddField(
  125 + model_name='flashcard',
  126 + name='mask',
  127 + field=models.ForeignKey(blank=True, to='flashcards.FlashcardMask', help_text=b'The default mask for this card', null=True),
  128 + ),
  129 + migrations.AddField(
  130 + model_name='flashcard',
  131 + name='previous',
  132 + field=models.ForeignKey(blank=True, to='flashcards.Flashcard', help_text=b'The previous version of this card, if one exists', null=True),
  133 + ),
  134 + migrations.AddField(
  135 + model_name='flashcard',
  136 + name='section',
  137 + field=models.ForeignKey(help_text=b'The section with which the card is associated', to='flashcards.Section'),
  138 + ),
  139 + migrations.AddField(
  140 + model_name='user',
  141 + name='sections',
  142 + field=models.ManyToManyField(to='flashcards.Section'),
  143 + ),
  144 + migrations.AddField(
  145 + model_name='user',
  146 + name='user_permissions',
  147 + field=models.ManyToManyField(related_query_name='user', related_name='user_set', to='auth.Permission', blank=True, help_text='Specific permissions for this user.', verbose_name='user permissions'),
  148 + ),
  149 + migrations.AlterUniqueTogether(
  150 + name='userflashcard',
  151 + unique_together=set([('user', 'flashcard')]),
  152 + ),
  153 + migrations.AlterIndexTogether(
  154 + name='userflashcard',
  155 + index_together=set([('user', 'flashcard')]),
  156 + ),
  157 + ]
flashcards/models.py View file @ 2b6bc76
1   -from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
  1 +from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin, AbstractUser
2 2 from django.contrib.auth.tests.custom_user import CustomUser
3 3 from django.db.models import *
4 4 from simple_email_confirmation import SimpleEmailConfirmationUserMixin
5 5  
  6 +# Hack to fix AbstractUser before subclassing it
  7 +AbstractUser._meta.get_field('email')._unique = True
6 8  
7   -class UserManager(BaseUserManager):
8   - def create_user(self, email, password=None):
9   - """
10   - Creates and saves a User with the given email, date of
11   - birth and password.
12   - """
13   - if not email:
14   - raise ValueError('Users must have an email address')
15   -
16   - user = self.model(email=self.normalize_email(email))
17   -
18   - user.set_password(password)
19   - user.save(using=self._db)
20   - return user
21   -
22   - def create_superuser(self, email, password):
23   - """
24   - Creates and saves a superuser with the given email and password.
25   - """
26   - user = self.create_user(email, password=password)
27   - user.is_staff = True
28   - user.save(using=self._db)
29   - return user
30   -
31   -
32   -class User(AbstractBaseUser, SimpleEmailConfirmationUserMixin, ):
  9 +class User(AbstractUser, SimpleEmailConfirmationUserMixin, ):
33 10 USERNAME_FIELD = 'email'
34 11 REQUIRED_FIELDS = []
35   -
36   - objects = UserManager()
37   - is_staff = BooleanField(default=False)
38   -
39   - email = EmailField(
40   - verbose_name='email address',
41   - max_length=255,
42   - unique=True,
43   - )
44   - date_joined = DateTimeField(auto_now_add=True)
45 12 sections = ManyToManyField('Section')
46 13  
47 14  
... ... @@ -52,7 +19,7 @@
52 19 2. A user used to have a flashcard in their deck
53 20 3. A user has a flashcard hidden from them
54 21 """
55   - user = ForeignKey(User)
  22 + user = ForeignKey('User')
56 23 mask = ForeignKey('FlashcardMask', help_text="A mask which overrides the card's mask")
57 24 pulled = DateTimeField(blank=True, null=True, help_text="When the user pulled the card")
58 25 flashcard = ForeignKey('Flashcard')
flashcards/serializers.py View file @ 2b6bc76
... ... @@ -18,8 +18,6 @@
18 18  
19 19  
20 20 class UserSerializer(HyperlinkedModelSerializer):
21   - """
22   - """
23 21 email = EmailField(required=False)
24 22  
25 23 class Meta:
flashy/settings.py View file @ 2b6bc76
... ... @@ -56,7 +56,10 @@
56 56 )
57 57  
58 58 ROOT_URLCONF = 'flashy.urls'
59   -
  59 +# Authentication backends
  60 +AUTHENTICATION_BACKENDS = (
  61 + 'django.contrib.auth.backends.ModelBackend',
  62 +)
60 63 TEMPLATES = [
61 64 {
62 65 'BACKEND': 'django.template.backends.django.DjangoTemplates',