Skip to content

Commit 6d4b31a

Browse files
committed
Complete Working App from boilerplate
0 parents  commit 6d4b31a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+2067
-0
lines changed

.bowerrc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"directory": "static/bower_components"
3+
}

.buildpacks

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
https://github.com/heroku/heroku-buildpack-python.git
2+
https://github.com/heroku/heroku-buildpack-nodejs.git

.gitignore

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Python compiled byte code
2+
*.pyc
3+
4+
# SQLite3 database
5+
*.sqlite3
6+
7+
# Node modules
8+
node_modules/
9+
10+
# Bower components
11+
static/bower_components/
12+
13+
# Uglified JavaScript
14+
dist/
15+
16+
# Staticfiles
17+
staticfiles/
18+
19+
# PyCharm
20+
.idea
21+
22+
# npm
23+
npm-debug.log
24+

Procfile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: gunicorn django_and_angular.wsgi --log-file -

README.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# thinkster-django-angular-boilerplate
2+
3+
## Installation
4+
5+
*NOTE: Requires [virtualenv](http://virtualenv.readthedocs.org/en/latest/),
6+
[virtualenvwrapper](http://virtualenvwrapper.readthedocs.org/en/latest/) and
7+
[Node.js](http://nodejs.org/).*
8+
9+
* Fork this repository.
10+
* `$ git clone [email protected]:<your username>/thinkster-django-angular-boilerplate.git`
11+
* `$ mkvirtualenv thinkster-djangular`
12+
* `$ cd thinkster-django-angular-boilerplate/`
13+
* `$ pip install -r requirements.txt`
14+
* `$ npm install -g bower`
15+
* `$ npm install`
16+
* `$ bower install`
17+
* `$ python manage.py migrate`
18+
* `$ python manage.py runserver`
19+

authentication/__init__.py

Whitespace-only changes.

authentication/admin.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.contrib import admin
2+
3+
# Register your models here.
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import unicode_literals
3+
4+
from django.db import models, migrations
5+
import django.utils.timezone
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name='Account',
16+
fields=[
17+
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
18+
('password', models.CharField(max_length=128, verbose_name='password')),
19+
('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login')),
20+
('email', models.EmailField(unique=True, max_length=75)),
21+
('username', models.CharField(unique=True, max_length=40)),
22+
('first_name', models.CharField(max_length=40, blank=True)),
23+
('last_name', models.CharField(max_length=40, blank=True)),
24+
('tagline', models.CharField(max_length=140, blank=True)),
25+
('is_admin', models.BooleanField(default=False)),
26+
('created_at', models.DateTimeField(auto_now_add=True)),
27+
('updated_at', models.DateTimeField(auto_now=True)),
28+
],
29+
options={
30+
'abstract': False,
31+
},
32+
bases=(models.Model,),
33+
),
34+
]

authentication/migrations/__init__.py

Whitespace-only changes.

authentication/models.py

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
2+
from django.db import models
3+
4+
5+
class AccountManager(BaseUserManager):
6+
def create_user(self, email, password=None, **kwargs):
7+
if not email:
8+
raise ValueError('Users must have a valid email address.')
9+
10+
if not kwargs.get('username'):
11+
raise ValueError('Users must have a valid username.')
12+
13+
account = self.model(
14+
email=self.normalize_email(email), username=kwargs.get('username')
15+
)
16+
17+
account.set_password(password)
18+
account.save()
19+
20+
return account
21+
22+
def create_superuser(self, email, password, **kwargs):
23+
account = self.create_user(email, password, **kwargs)
24+
25+
account.is_admin = True
26+
account.save()
27+
28+
return account
29+
30+
31+
class Account(AbstractBaseUser):
32+
email = models.EmailField(unique=True)
33+
username = models.CharField(max_length=40, unique=True)
34+
35+
first_name = models.CharField(max_length=40, blank=True)
36+
last_name = models.CharField(max_length=40, blank=True)
37+
tagline = models.CharField(max_length=140, blank=True)
38+
39+
is_admin = models.BooleanField(default=False)
40+
41+
created_at = models.DateTimeField(auto_now_add=True)
42+
updated_at = models.DateTimeField(auto_now=True)
43+
44+
objects = AccountManager()
45+
46+
USERNAME_FIELD = 'email'
47+
REQUIRED_FIELDS = ['username']
48+
49+
def __unicode__(self):
50+
return self.email
51+
52+
def get_full_name(self):
53+
return ' '.join([self.first_name, self.last_name])
54+
55+
def get_short_name(self):
56+
return self.first_name

authentication/permissions.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from rest_framework import permissions
2+
3+
4+
class IsAccountOwner(permissions.BasePermission):
5+
def has_object_permission(self, request, view, account):
6+
if request.user:
7+
return account == request.user
8+
return False

authentication/serializers.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from django.contrib.auth import update_session_auth_hash
2+
3+
from rest_framework import serializers
4+
5+
from authentication.models import Account
6+
7+
8+
class AccountSerializer(serializers.ModelSerializer):
9+
password = serializers.CharField(write_only=True, required=False)
10+
confirm_password = serializers.CharField(write_only=True, required=False)
11+
12+
class Meta:
13+
model = Account
14+
fields = ('id', 'email', 'username', 'created_at', 'updated_at',
15+
'first_name', 'last_name', 'tagline', 'password',
16+
'confirm_password',)
17+
read_only_fields = ('created_at', 'updated_at',)
18+
19+
def create(self, validated_data):
20+
return Account.objects.create(**validated_data)
21+
22+
def update(self, instance, validated_data):
23+
instance.username = validated_data.get('username', instance.username)
24+
instance.tagline = validated_data.get('tagline', instance.tagline)
25+
26+
instance.save()
27+
28+
password = validated_data.get('password', None)
29+
confirm_password = validated_data.get('confirm_password', None)
30+
31+
if password and confirm_password and password == confirm_password:
32+
instance.set_password(password)
33+
instance.save()
34+
35+
update_session_auth_hash(self.context.get('request'), instance)
36+
37+
return instance

authentication/tests.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.test import TestCase
2+
3+
# Create your tests here.

authentication/views.py

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import json
2+
3+
from django.contrib.auth import authenticate, login, logout
4+
5+
from rest_framework import permissions, viewsets, status, views
6+
from rest_framework.response import Response
7+
8+
from authentication.models import Account
9+
from authentication.permissions import IsAccountOwner
10+
from authentication.serializers import AccountSerializer
11+
12+
13+
class AccountViewSet(viewsets.ModelViewSet):
14+
lookup_field = 'username'
15+
queryset = Account.objects.all()
16+
serializer_class = AccountSerializer
17+
18+
def get_permissions(self):
19+
if self.request.method in permissions.SAFE_METHODS:
20+
return (permissions.AllowAny(),)
21+
22+
if self.request.method == 'POST':
23+
return (permissions.AllowAny(),)
24+
25+
return (permissions.IsAuthenticated(), IsAccountOwner(),)
26+
27+
def create(self, request):
28+
serializer = self.serializer_class(data=request.data)
29+
30+
if serializer.is_valid():
31+
Account.objects.create_user(**serializer.validated_data)
32+
33+
return Response(serializer.validated_data, status=status.HTTP_201_CREATED)
34+
35+
return Response({
36+
'status': 'Bad request',
37+
'message': 'Account could not be created with received data.'
38+
}, status=status.HTTP_400_BAD_REQUEST)
39+
40+
41+
class LoginView(views.APIView):
42+
def post(self, request, format=None):
43+
data = json.loads(request.body)
44+
45+
email = data.get('email', None)
46+
password = data.get('password', None)
47+
48+
account = authenticate(email=email, password=password)
49+
50+
if account is not None:
51+
if account.is_active:
52+
login(request, account)
53+
54+
serialized = AccountSerializer(account)
55+
56+
return Response(serialized.data)
57+
else:
58+
return Response({
59+
'status': 'Unauthorized',
60+
'message': 'This account has been disabled.'
61+
}, status=status.HTTP_401_UNAUTHORIZED)
62+
else:
63+
return Response({
64+
'status': 'Unauthorized',
65+
'message': 'Username/password combination invalid.'
66+
}, status=status.HTTP_401_UNAUTHORIZED)
67+
68+
69+
class LogoutView(views.APIView):
70+
permission_classes = (permissions.IsAuthenticated,)
71+
72+
def post(self, request, format=None):
73+
logout(request)
74+
75+
return Response({}, status=status.HTTP_204_NO_CONTENT)

bower.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "django_and_angular",
3+
"version": "0.0.0",
4+
"homepage": "https://github.com/sshishov/DjangoAndAngular",
5+
"license": "MIT",
6+
"ignore": [
7+
"**/.*",
8+
"node_modules",
9+
"bower_components",
10+
"test",
11+
"tests"
12+
],
13+
"dependencies": {
14+
"angular": "~1.3.1",
15+
"angular-route": "~1.3.1",
16+
"angular-cookies": "~1.3.1",
17+
"bootstrap": "~3.3.0",
18+
"bootstrap-material-design": "~0.1.5",
19+
"jquery": "~2.1.1",
20+
"ngDialog": "~0.3.3",
21+
"underscore": "~1.7.0"
22+
}
23+
}

django_and_angular/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)