Commit 18095ed465f262ac37f8cbef2425ec50ffd48bec

Authored by Andrew Buss
1 parent 2dc11d15d8
Exists in master

Integrated django-simple-email-confirmation

Showing 14 changed files with 117 additions and 367 deletions Inline Diff

*~ 1 1 *~
venv* 2 2 venv*
static* 3 3 static*
*.pyc 4 4 *.pyc
.idea* 5 5 .idea*
.*.swp 6 6 .*.swp
*.sqlite3 7 7 *.sqlite3
8 secrets
flashcards/api.py View file @ 18095ed
from django.http import Http404 1 1 from django.core.mail import send_mail
from rest_framework.views import APIView 2 2 from rest_framework.views import APIView
from rest_framework.response import Response 3 3 from rest_framework.response import Response
from rest_framework import status 4 4 from rest_framework import status
from rest_framework.exceptions import ValidationError 5 5 from rest_framework.exceptions import ValidationError
from flashcards.serializers import * 6 6 from flashcards.serializers import *
from django.http import HttpResponse 7
from rest_framework.renderers import JSONRenderer 8
9 7
class JSONResponse(HttpResponse): 10
""" 11
An HttpResponse that renders its content into JSON. 12
""" 13
def __init__(self, data, **kwargs): 14
content = JSONRenderer().render(data) 15
kwargs['content_type'] = 'application/json' 16
super(JSONResponse, self).__init__(content, **kwargs) 17
18 8
19
class UserDetail(APIView): 20 9 class UserDetail(APIView):
def patch(self, request,format=None): 21 10 def patch(self, request, format=None):
""" 22 11 """
Updates a user's password after they enter a valid old password. 23 12 Updates a user's password after they enter a valid old password.
TODO: email verification 24 13 TODO: email verification
""" 25 14 """
currentUser = request.user 26 15
if 'old_password' not in request.data: 27 16 if 'old_password' not in request.data:
raise ValidationError('Old password is required') 28 17 raise ValidationError('Old password is required')
if 'new_password' not in request.data: 29 18 if 'new_password' not in request.data:
raise ValidationError('New password is required') 30 19 raise ValidationError('New password is required')
if not request.data['new_password']: 31 20 if not request.data['new_password']:
raise ValidationError('Password cannot be blank') 32 21 raise ValidationError('Password cannot be blank')
if not currentUser.check_password(request.data['old_password']): 33 22
raise ValidationError('Invalid old password') 34 23 currentuser = request.user
currentUser.set_password(request.data['new_password']) 35 24
currentUser.save() 36 25 if not currentuser.check_password(request.data['old_password']):
26 raise ValidationError('Invalid old password')
27
28 currentuser.set_password(request.data['new_password'])
29 currentuser.save()
30
return Response(status=status.HTTP_204_NO_CONTENT) 37 31 return Response(status=status.HTTP_204_NO_CONTENT)
38 32
def get(self, request,format=None): 39 33 def get(self, request, format=None):
serializer = UserSerializer(request.user) 40 34 serializer = UserSerializer(request.user)
return Response(serializer.data) 41 35 return Response(serializer.data)
36
37 def post(self, request, format=None):
38 if 'email' not in request.data:
39 raise ValidationError('Email is required')
40 if 'password' not in request.data:
41 raise ValidationError('Password is required')
42
43 email = request.data['email']
44 user = User.objects.create_user(email)
45
46 body = '''
47 Visit the following link to confirm your email address:
48 http://flashy.cards/app/verify_email/%s
49
50 If you did not register for Flashy, no action is required.
51 '''
52
53 send_mail("Please verify your Flashy account",
54 body % user.confirmation_key,
55 "noreply@flashy.cards",
56 [user.email])
57
58 return Response(User)
42 59
60
flashcards/migrations/0001_initial.py View file @ 18095ed
# -*- coding: utf-8 -*- 1 File was deleted
from __future__ import unicode_literals 2
3
from django.db import models, migrations 4
from django.conf import settings 5
6
7
class Migration(migrations.Migration): 8
9
dependencies = [ 10
migrations.swappable_dependency(settings.AUTH_USER_MODEL), 11
] 12
13
operations = [ 14
migrations.CreateModel( 15
name='Class', 16
fields=[ 17
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 18
('department', models.CharField(max_length=50)), 19
('course_num', models.IntegerField()), 20
('name', models.CharField(max_length=50)), 21
('professor', models.CharField(max_length=50)), 22
('quarter', models.CharField(max_length=4)), 23
('members', models.ManyToManyField(to=settings.AUTH_USER_MODEL)), 24
], 25
), 26
migrations.CreateModel( 27
name='Flashcard', 28
fields=[ 29
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 30
('text', models.CharField(max_length=255)), 31
('pushed', models.DateTimeField()), 32
('material_date', models.DateTimeField()), 33
('hidden', models.CharField(max_length=255, null=True, blank=True)), 34
('associated_class', models.ForeignKey(to='flashcards.Class')), 35
('author', models.ForeignKey(to=settings.AUTH_USER_MODEL)), 36
], 37
), 38
migrations.CreateModel( 39
name='FlashcardMask', 40
fields=[ 41
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 42
('ranges', models.CharField(max_length=255)), 43
], 44
), 45
migrations.CreateModel( 46
name='UserFlashcard', 47
fields=[ 48
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 49
('pulled', models.DateTimeField(null=True)), 50
('unpulled', models.DateTimeField(null=True)), 51
('flashcard', models.ForeignKey(to='flashcards.Flashcard')), 52
('mask', models.ForeignKey(to='flashcards.FlashcardMask')), 53
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)), 54
], 55
), 56
migrations.CreateModel( 57
name='UserFlashCardReview', 58
fields=[ 59
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 60
('when', models.DateTimeField()), 61
('blanked_word', models.CharField(max_length=8)), 62
('response', models.CharField(max_length=255, null=True, blank=True)), 63
('correct', models.NullBooleanField()), 64
('user_flashcard', models.ForeignKey(to='flashcards.UserFlashcard')), 65
], 66
), 67
migrations.AddField( 68
model_name='flashcard', 69
name='mask', 70
field=models.ForeignKey(to='flashcards.FlashcardMask', null=True), 71
), 72
migrations.AddField( 73
flashcards/migrations/0002_auto_20150429_0248.py View file @ 18095ed
# -*- coding: utf-8 -*- 1 File was deleted
from __future__ import unicode_literals 2
3
from django.db import models, migrations 4
5
6
class Migration(migrations.Migration): 7
8
dependencies = [ 9
('flashcards', '0001_initial'), 10
] 11
12
operations = [ 13
migrations.AlterModelOptions( 14
name='userflashcard', 15
options={'ordering': ['-pulled']}, 16
), 17
migrations.AlterUniqueTogether( 18
name='userflashcard', 19
unique_together=set([('user', 'flashcard')]), 20
), 21
flashcards/migrations/0003_auto_20150429_0344.py View file @ 18095ed
# -*- coding: utf-8 -*- 1 File was deleted
from __future__ import unicode_literals 2
3
from django.db import models, migrations 4
5
6
class Migration(migrations.Migration): 7
8
dependencies = [ 9
('flashcards', '0002_auto_20150429_0248'), 10
] 11
12
operations = [ 13
migrations.AlterModelOptions( 14
name='class', 15
options={'ordering': ['-quarter']}, 16
), 17
migrations.AlterModelOptions( 18
name='flashcard', 19
options={'ordering': ['-pushed']}, 20
), 21
migrations.RenameField( 22
model_name='class', 23
old_name='professor', 24
new_name='instructor', 25
), 26
migrations.RemoveField( 27
model_name='flashcard', 28
name='hidden', 29
), 30
migrations.AddField( 31
model_name='flashcard', 32
name='hide_reason', 33
field=models.CharField(help_text=b'Reason for hiding this card', max_length=255, blank=True), 34
), 35
migrations.AddField( 36
model_name='flashcard', 37
name='is_hidden', 38
field=models.BooleanField(default=False), 39
), 40
migrations.AlterField( 41
model_name='flashcard', 42
name='associated_class', 43
field=models.ForeignKey(help_text=b'The class with which the card is associated', to='flashcards.Class'), 44
), 45
migrations.AlterField( 46
model_name='flashcard', 47
name='mask', 48
field=models.ForeignKey(blank=True, to='flashcards.FlashcardMask', help_text=b'The default mask for this card', null=True), 49
), 50
migrations.AlterField( 51
model_name='flashcard', 52
name='material_date', 53
field=models.DateTimeField(help_text=b'The date with which the card is associated'), 54
), 55
migrations.AlterField( 56
model_name='flashcard', 57
name='previous', 58
field=models.ForeignKey(blank=True, to='flashcards.Flashcard', help_text=b'The previous version of this card, if one exists', null=True), 59
), 60
migrations.AlterField( 61
model_name='flashcard', 62
name='pushed', 63
field=models.DateTimeField(help_text=b'When the card was first pushed', auto_now_add=True), 64
), 65
migrations.AlterField( 66
model_name='flashcard', 67
name='text', 68
field=models.CharField(help_text=b'The text on the card', max_length=255), 69
), 70
migrations.AlterField( 71
model_name='userflashcard', 72
name='mask', 73
field=models.ForeignKey(help_text=b"A mask which overrides the card's mask", to='flashcards.FlashcardMask'), 74
), 75
migrations.AlterField( 76
model_name='userflashcard', 77
name='pulled', 78
field=models.DateTimeField(help_text=b'When the user pulled the card', null=True, blank=True), 79
), 80
migrations.AlterField( 81
model_name='userflashcard', 82
name='unpulled', 83
field=models.DateTimeField(help_text=b'When the user unpulled this card', null=True, blank=True), 84
), 85
migrations.AlterField( 86
model_name='userflashcardreview', 87
name='blanked_word', 88
field=models.CharField(help_text=b'The character range which was blanked', max_length=8, blank=True), 89
), 90
migrations.AlterField( 91
model_name='userflashcardreview', 92
name='correct', 93
field=models.NullBooleanField(help_text=b"The user's self-evaluation of their response"), 94
), 95
migrations.AlterField( 96
model_name='userflashcardreview', 97
name='response', 98
field=models.CharField(help_text=b"The user's response", max_length=255, null=True, blank=True), 99
), 100
flashcards/migrations/0004_auto_20150429_0827.py View file @ 18095ed
# -*- coding: utf-8 -*- 1 File was deleted
from __future__ import unicode_literals 2
3
from django.db import models, migrations 4
5
6
class Migration(migrations.Migration): 7
8
dependencies = [ 9
('flashcards', '0003_auto_20150429_0344'), 10
] 11
12
operations = [ 13
migrations.CreateModel( 14
name='LecturePeriod', 15
fields=[ 16
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 17
('week_day', models.IntegerField(help_text=b'0-indexed day of week, starting at Monday')), 18
('start_time', models.TimeField()), 19
('end_time', models.TimeField()), 20
], 21
), 22
migrations.RenameModel( 23
old_name='Class', 24
new_name='Section', 25
), 26
migrations.RemoveField( 27
model_name='flashcard', 28
name='associated_class', 29
), 30
migrations.AddField( 31
model_name='flashcard', 32
name='section', 33
field=models.ForeignKey(default=None, to='flashcards.Section', help_text=b'The section with which the card is associated'), 34
preserve_default=False, 35
), 36
migrations.AddField( 37
flashcards/migrations/0005_auto_20150430_0557.py View file @ 18095ed
# -*- coding: utf-8 -*- 1 File was deleted
from __future__ import unicode_literals 2
3
from django.db import models, migrations 4
5
6
class Migration(migrations.Migration): 7
8
dependencies = [ 9
('flashcards', '0004_auto_20150429_0827'), 10
] 11
12
operations = [ 13
migrations.RenameField( 14
model_name='section', 15
old_name='name', 16
new_name='course_title', 17
), 18
migrations.RenameField( 19
model_name='section', 20
old_name='instructor', 21
new_name='professor', 22
), 23
flashcards/migrations/0006_auto_20150430_0643.py View file @ 18095ed
# -*- coding: utf-8 -*- 1 File was deleted
from __future__ import unicode_literals 2
3
from django.db import models, migrations 4
5
6
class Migration(migrations.Migration): 7
8
dependencies = [ 9
('flashcards', '0005_auto_20150430_0557'), 10
] 11
12
operations = [ 13
migrations.AlterField( 14
flashcards/migrations/0007_auto_20150430_0657.py View file @ 18095ed
# -*- coding: utf-8 -*- 1 File was deleted
from __future__ import unicode_literals 2
3
from django.db import models, migrations 4
5
6
class Migration(migrations.Migration): 7
8
dependencies = [ 9
('flashcards', '0006_auto_20150430_0643'), 10
] 11
12
operations = [ 13
migrations.RenameField( 14
model_name='section', 15
old_name='professor', 16
new_name='instructor', 17
), 18
flashcards/models.py View file @ 18095ed
from django.contrib.auth.models import User 1 1 from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
2 from django.contrib.auth.tests.custom_user import CustomUser
from django.db.models import * 2 3 from django.db.models import *
4 from simple_email_confirmation import SimpleEmailConfirmationUserMixin
3 5
4 6
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_admin = True
28 user.save(using=self._db)
29 return user
30
31
32 class User(AbstractBaseUser, SimpleEmailConfirmationUserMixin):
33 USERNAME_FIELD = 'email'
34 REQUIRED_FIELDS = []
35
36 objects = UserManager()
37
38 email = EmailField(
39 verbose_name='email address',
40 max_length=255,
41 unique=True,
42 )
43 date_joined = DateTimeField(auto_now_add=True)
44 sections = ManyToManyField('Section')
45
46
class UserFlashcard(Model): 5 47 class UserFlashcard(Model):
""" 6 48 """
Represents the relationship between a user and a flashcard by: 7 49 Represents the relationship between a user and a flashcard by:
1. A user has a flashcard in their deck 8 50 1. A user has a flashcard in their deck
2. A user used to have a flashcard in their deck 9 51 2. A user used to have a flashcard in their deck
3. A user has a flashcard hidden from them 10 52 3. A user has a flashcard hidden from them
""" 11 53 """
user = ForeignKey(User) 12 54 user = ForeignKey(User)
mask = ForeignKey('FlashcardMask', help_text="A mask which overrides the card's mask") 13 55 mask = ForeignKey('FlashcardMask', help_text="A mask which overrides the card's mask")
pulled = DateTimeField(blank=True, null=True, help_text="When the user pulled the card") 14 56 pulled = DateTimeField(blank=True, null=True, help_text="When the user pulled the card")
flashcard = ForeignKey('Flashcard') 15 57 flashcard = ForeignKey('Flashcard')
unpulled = DateTimeField(blank=True, null=True, help_text="When the user unpulled this card") 16 58 unpulled = DateTimeField(blank=True, null=True, help_text="When the user unpulled this card")
17 59
class Meta: 18 60 class Meta:
# There can be at most one UserFlashcard for each User and Flashcard 19 61 # There can be at most one UserFlashcard for each User and Flashcard
unique_together = (('user', 'flashcard'),) 20 62 unique_together = (('user', 'flashcard'),)
index_together = ["user", "flashcard"] 21 63 index_together = ["user", "flashcard"]
# By default, order by most recently pulled 22 64 # By default, order by most recently pulled
ordering = ['-pulled'] 23 65 ordering = ['-pulled']
24 66
def is_hidden(self): 25 67 def is_hidden(self):
""" 26 68 """
A card is hidden only if a user has not ever added it to their deck. 27 69 A card is hidden only if a user has not ever added it to their deck.
:return: Whether the flashcard is hidden from the user 28 70 :return: Whether the flashcard is hidden from the user
""" 29 71 """
return not self.pulled 30 72 return not self.pulled
31 73
def is_in_deck(self): 32 74 def is_in_deck(self):
""" 33 75 """
:return:Whether the flashcard is in the user's deck 34 76 :return:Whether the flashcard is in the user's deck
""" 35 77 """
return self.pulled and not self.unpulled 36 78 return self.pulled and not self.unpulled
37 79
38 80
class FlashcardMask(Model): 39 81 class FlashcardMask(Model):
""" 40 82 """
A serialized list of character ranges that can be blanked out during review. 41 83 A serialized list of character ranges that can be blanked out during review.
This is encoded as '13-145,150-195' 42 84 This is encoded as '13-145,150-195'
""" 43 85 """
ranges = CharField(max_length=255) 44 86 ranges = CharField(max_length=255)
45 87
46 88
class Flashcard(Model): 47 89 class Flashcard(Model):
text = CharField(max_length=255, help_text='The text on the card') 48 90 text = CharField(max_length=255, help_text='The text on the card')
section = ForeignKey('Section', help_text='The section with which the card is associated') 49 91 section = ForeignKey('Section', help_text='The section with which the card is associated')
pushed = DateTimeField(auto_now_add=True, help_text="When the card was first pushed") 50 92 pushed = DateTimeField(auto_now_add=True, help_text="When the card was first pushed")
material_date = DateTimeField(help_text="The date with which the card is associated") 51 93 material_date = DateTimeField(help_text="The date with which the card is associated")
previous = ForeignKey('Flashcard', null=True, blank=True, 52 94 previous = ForeignKey('Flashcard', null=True, blank=True,
help_text="The previous version of this card, if one exists") 53 95 help_text="The previous version of this card, if one exists")
author = ForeignKey(User) 54 96 author = ForeignKey(User)
is_hidden = BooleanField(default=False) 55 97 is_hidden = BooleanField(default=False)
hide_reason = CharField(blank=True, max_length=255, help_text="Reason for hiding this card") 56 98 hide_reason = CharField(blank=True, max_length=255, help_text="Reason for hiding this card")
mask = ForeignKey(FlashcardMask, blank=True, null=True, help_text="The default mask for this card") 57 99 mask = ForeignKey(FlashcardMask, blank=True, null=True, help_text="The default mask for this card")
58 100
class Meta: 59 101 class Meta:
# By default, order by most recently pushed 60 102 # By default, order by most recently pushed
ordering = ['-pushed'] 61 103 ordering = ['-pushed']
62 104
def is_hidden_from(self, user): 63 105 def is_hidden_from(self, user):
""" 64 106 """
A card can be hidden globally, but if a user has the card in their deck, 65 107 A card can be hidden globally, but if a user has the card in their deck,
this visibility overrides a global hide. 66 108 this visibility overrides a global hide.
:param user: 67 109 :param user:
:return: Whether the card is hidden from the user. 68 110 :return: Whether the card is hidden from the user.
""" 69 111 """
result = user.userflashcard_set.filter(flashcard=self) 70 112 result = user.userflashcard_set.filter(flashcard=self)
if not result.exists(): return self.is_hidden 71 113 if not result.exists(): return self.is_hidden
return result[0].is_hidden() 72 114 return result[0].is_hidden()
73 115
74 116
@classmethod 75 117 @classmethod
def cards_visible_to(cls, user): 76 118 def cards_visible_to(cls, user):
""" 77 119 """
:param user: 78 120 :param user:
:return: A queryset with all cards that should be visible to a user. 79 121 :return: A queryset with all cards that should be visible to a user.
""" 80 122 """
return cls.objects.filter(hidden=False).exclude(userflashcard=user, userflashcard__pulled=None) 81 123 return cls.objects.filter(hidden=False).exclude(userflashcard=user, userflashcard__pulled=None)
82 124
83 125
class UserFlashcardReview(Model): 84 126 class UserFlashcardReview(Model):
""" 85 127 """
An event of a user reviewing a flashcard. 86 128 An event of a user reviewing a flashcard.
""" 87 129 """
user_flashcard = ForeignKey(UserFlashcard) 88 130 user_flashcard = ForeignKey(UserFlashcard)
when = DateTimeField() 89 131 when = DateTimeField()
blanked_word = CharField(max_length=8, blank=True, help_text="The character range which was blanked") 90 132 blanked_word = CharField(max_length=8, blank=True, help_text="The character range which was blanked")
response = CharField(max_length=255, blank=True, null=True, help_text="The user's response") 91 133 response = CharField(max_length=255, blank=True, null=True, help_text="The user's response")
correct = NullBooleanField(help_text="The user's self-evaluation of their response") 92 134 correct = NullBooleanField(help_text="The user's self-evaluation of their response")
93 135
def status(self): 94 136 def status(self):
""" 95 137 """
There are three stages of a review object: 96 138 There are three stages of a review object:
1. the user has been shown the card 97 139 1. the user has been shown the card
2. the user has answered the card 98 140 2. the user has answered the card
3. the user has self-evaluated their response's correctness 99 141 3. the user has self-evaluated their response's correctness
100 142
:return: string (evaluated, answered, viewed) 101 143 :return: string (evaluated, answered, viewed)
""" 102 144 """
if self.correct is not None: return "evaluated" 103 145 if self.correct is not None: return "evaluated"
if self.response: return "answered" 104 146 if self.response: return "answered"
return "viewed" 105 147 return "viewed"
106 148
149
class Section(Model): 107 150 class Section(Model):
""" 108 151 """
A UCSD course taught by an instructor during a quarter. 109 152 A UCSD course taught by an instructor during a quarter.
Different sections taught by the same instructor in the same quarter are considered identical. 110 153 Different sections taught by the same instructor in the same quarter are considered identical.
We use the term "section" to avoid collision with the builtin keyword "class" 111 154 We use the term "section" to avoid collision with the builtin keyword "class"
""" 112 155 """
department = CharField(max_length=50) 113 156 department = CharField(max_length=50)
flashcards/serializers.py View file @ 18095ed
from flashcards.models import Section, LecturePeriod 1 1 from flashcards.models import Section, LecturePeriod, User
2 from rest_framework.fields import EmailField
from rest_framework.relations import HyperlinkedRelatedField 2 3 from rest_framework.relations import HyperlinkedRelatedField
from rest_framework.serializers import HyperlinkedModelSerializer 3 4 from rest_framework.serializers import HyperlinkedModelSerializer
from django.contrib.auth.models import User 4
5 5
6
class SectionSerializer(HyperlinkedModelSerializer): 6 7 class SectionSerializer(HyperlinkedModelSerializer):
lectureperiod_set = HyperlinkedRelatedField(many=True, view_name='lectureperiod-detail', read_only=True) 7 8 lectureperiod_set = HyperlinkedRelatedField(many=True, view_name='lectureperiod-detail', read_only=True)
9
class Meta: 8 10 class Meta:
model = Section 9 11 model = Section
exclude = ('members',) 10 12 exclude = ('members',)
11 13
12 14
class LecturePeriodSerializer(HyperlinkedModelSerializer): 13 15 class LecturePeriodSerializer(HyperlinkedModelSerializer):
class Meta: 14 16 class Meta:
model = LecturePeriod 15 17 model = LecturePeriod
16 18
19
class UserSerializer(HyperlinkedModelSerializer): 17 20 class UserSerializer(HyperlinkedModelSerializer):
""" 18 21 """
""" 19 22 """
23 email = EmailField(required=False)
24
class Meta: 20 25 class Meta:
model = User 21 26 model = User
flashcards/views.py View file @ 18095ed
from flashcards.models import Section, LecturePeriod 1 1 from flashcards.models import Section, LecturePeriod
from flashcards.serializers import SectionSerializer, LecturePeriodSerializer 2 2 from flashcards.serializers import SectionSerializer, LecturePeriodSerializer
from rest_framework.permissions import IsAuthenticatedOrReadOnly 3 3 from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.viewsets import ModelViewSet 4 4 from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination 5 5 from rest_framework.pagination import PageNumberPagination
from django.core.paginator import Paginator 6
7 6
7
class StandardResultsSetPagination(PageNumberPagination): 8 8 class StandardResultsSetPagination(PageNumberPagination):
page_size = 40 9 9 page_size = 40
page_size_query_param = 'page_size' 10 10 page_size_query_param = 'page_size'
max_page_size = 1000 11 11 max_page_size = 1000
12 12
13
class SectionViewSet(ModelViewSet): 13 14 class SectionViewSet(ModelViewSet):
queryset = Section.objects.all() 14 15 queryset = Section.objects.all()
serializer_class = SectionSerializer 15 16 serializer_class = SectionSerializer
permission_classes = (IsAuthenticatedOrReadOnly,) 16 17 permission_classes = (IsAuthenticatedOrReadOnly,)
pagination_class = StandardResultsSetPagination 17 18 pagination_class = StandardResultsSetPagination
19
18 20
class LecturePeriodViewSet(ModelViewSet): 19 21 class LecturePeriodViewSet(ModelViewSet):
queryset = LecturePeriod.objects.all() 20 22 queryset = LecturePeriod.objects.all()
flashy/settings.py View file @ 18095ed
""" 1 1 """
Django settings for flashy project. 2 2 Django settings for flashy project.
3 3
Generated by 'django-admin startproject' using Django 1.8. 4 4 Generated by 'django-admin startproject' using Django 1.8.
5 5
For more information on this file, see 6 6 For more information on this file, see
https://docs.djangoproject.com/en/1.8/topics/settings/ 7 7 https://docs.djangoproject.com/en/1.8/topics/settings/
8 8
For the full list of settings and their values, see 9 9 For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/ 10 10 https://docs.djangoproject.com/en/1.8/ref/settings/
""" 11 11 """
12 12
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) 13 13 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os 14 14 import os
15 15
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 16 16 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 17
18
# Quick-start development settings - unsuitable for production 19
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ 20
21
# SECURITY WARNING: keep the secret key used in production secret! 22
SECRET_KEY = '8)#-j&8dghe-y&v4a%r6u#y@r86&6nfv%k$(a((r-zh$m3ct!9' 23
24
# SECURITY WARNING: don't run with debug turned on in production! 25 18 # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True 26 19 DEBUG = True
27 20
ALLOWED_HOSTS = [] 28 21 ALLOWED_HOSTS = []
29 22
30 23 AUTH_USER_MODEL = 'flashcards.User'
# Application definition 31 24 # Application definition
32 25
INSTALLED_APPS = ( 33 26 INSTALLED_APPS = (
27 'simple_email_confirmation',
28 'flashcards',
'django.contrib.admin', 34 29 'django.contrib.admin',
'django.contrib.admindocs', 35 30 'django.contrib.admindocs',
'django.contrib.auth', 36 31 'django.contrib.auth',
'django.contrib.contenttypes', 37 32 'django.contrib.contenttypes',
'django.contrib.sessions', 38 33 'django.contrib.sessions',
'django.contrib.messages', 39 34 'django.contrib.messages',
'django.contrib.staticfiles', 40 35 'django.contrib.staticfiles',
36 'django_ses',
'rest_framework', 41 37 'rest_framework',
'flashcards', 42 38
39
) 43 40 )
44 41
REST_FRAMEWORK = { 45 42 REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination', 46 43 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',
'PAGE_SIZE': 20 47 44 'PAGE_SIZE': 20
} 48 45 }
49 46
MIDDLEWARE_CLASSES = ( 50 47 MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware', 51 48 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 52 49 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 53 50 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 54 51 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 55 52 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 56 53 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 57 54 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware', 58 55 'django.middleware.security.SecurityMiddleware',
) 59 56 )
60 57
ROOT_URLCONF = 'flashy.urls' 61 58 ROOT_URLCONF = 'flashy.urls'
62 59
TEMPLATES = [ 63 60 TEMPLATES = [
{ 64 61 {
'BACKEND': 'django.template.backends.django.DjangoTemplates', 65 62 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['templates/'], 66 63 'DIRS': ['templates/'],
'APP_DIRS': True, 67 64 'APP_DIRS': True,
'OPTIONS': { 68 65 'OPTIONS': {
'context_processors': [ 69 66 'context_processors': [
'django.template.context_processors.debug', 70 67 'django.template.context_processors.debug',
'django.template.context_processors.request', 71 68 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 72 69 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 73 70 'django.contrib.messages.context_processors.messages',
], 74 71 ],
}, 75 72 },
}, 76 73 },
] 77 74 ]
78 75
WSGI_APPLICATION = 'flashy.wsgi.application' 79 76 WSGI_APPLICATION = 'flashy.wsgi.application'
80 77
81 78
# Database 82 79 # Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases 83 80 # https://docs.djangoproject.com/en/1.8/ref/settings/#databases
84 81
DATABASES = { 85 82 DATABASES = {
'default': { 86 83 'default': {
requirements.txt View file @ 18095ed
beautifulsoup4 1 1 beautifulsoup4
Django>=1.8 2 2 Django>=1.8
#django-websocket-redis==0.4.3 3 3 #django-websocket-redis==0.4.3
#gevent==1.0.1 4 4 #gevent==1.0.1
#greenlet==0.4.5 5 5 #greenlet==0.4.5
#redis==2.10.3 6 6 #redis==2.10.3
six==1.9.0 7 7 six==1.9.0
djangorestframework 8 8 djangorestframework
docutils 9 9 docutils
gunicorn 10 10 gunicorn
11 django-simple-email-confirmation
12 django-ses