Skip to content

Commit 5ef8d63

Browse files
author
Emmanouil Konstantinidis
committed
Demo apps
1 parent dc023a0 commit 5ef8d63

File tree

12 files changed

+292
-0
lines changed

12 files changed

+292
-0
lines changed

demo/project/accounts/__init__.py

Whitespace-only changes.

demo/project/accounts/models.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from django.db import models
2+
from django.contrib.auth.models import AbstractBaseUser
3+
4+
5+
class User(AbstractBaseUser):
6+
created = models.DateTimeField(auto_now_add=True, db_index=True)
7+
modified = models.DateTimeField(auto_now=True)
8+
9+
email = models.EmailField(unique=True, verbose_name='email address', max_length=255)
10+
full_name = models.CharField(max_length=255)
11+
12+
is_active = models.BooleanField(default=False)
13+
is_admin = models.BooleanField(default=False)
14+
15+
USERNAME_FIELD = 'email'
16+
REQUIRED_FIELDS = ['email', 'full_name']
17+
18+
def __str__(self):
19+
return self.email
20+
21+
def has_perm(self, perm, obj=None):
22+
"Does the user have a specific permission?"
23+
# Simplest possible answer: Yes, always
24+
return True
25+
26+
def has_module_perms(self, app_label):
27+
"Does the user have permissions to view the app `app_label`?"
28+
# Simplest possible answer: Yes, always
29+
return True
30+
31+
@property
32+
def is_staff(self):
33+
"Is the user a member of staff?"
34+
# Simplest possible answer: All admins are staff
35+
return self.is_admin

demo/project/accounts/serializers.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from rest_framework import serializers
2+
from project.accounts.models import User
3+
4+
5+
class UserRegistrationSerializer(serializers.ModelSerializer):
6+
7+
class Meta:
8+
model = User
9+
fields = ('email', 'full_name', 'password',)
10+
extra_kwargs = {'password': {'write_only': True}}
11+
12+
13+
class UserProfileSerializer(serializers.ModelSerializer):
14+
15+
class Meta:
16+
model = User
17+
fields = ('email', 'full_name', 'password', 'is_active')
18+
extra_kwargs = {
19+
'password': {'write_only': True}
20+
}
21+
read_only_fields = ('is_active',)
22+
23+
24+
class ResetPasswordSerializer(serializers.ModelSerializer):
25+
26+
id = serializers.CharField()
27+
token = serializers.CharField()
28+
29+
class Meta:
30+
model = User
31+
fields = ('id', 'token', 'password',)
32+
extra_kwargs = {'password': {'write_only': True}}

demo/project/accounts/urls.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from django.conf.urls import url
2+
from project.accounts import views
3+
4+
5+
urlpatterns = [
6+
url(r'^test/$', views.TestView.as_view(), name="test-view"),
7+
8+
url(r'^login/$', views.LoginView.as_view(), name="login"),
9+
url(r'^register/$', views.UserRegistrationView.as_view(), name="register"),
10+
url(r'^reset-password/$', view=views.PasswordResetView.as_view(), name="reset-password"),
11+
url(r'^reset-password/confirm/$', views.PasswordResetConfirmView.as_view(), name="reset-password-confirm"),
12+
13+
url(r'^user/profile/$', views.UserProfileView.as_view(), name="profile"),
14+
15+
]

demo/project/accounts/views.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
from django.shortcuts import get_object_or_404
2+
from django.views.generic.base import TemplateView
3+
from rest_framework import parsers, renderers, generics, status
4+
from rest_framework.authtoken.models import Token
5+
from rest_framework.authtoken.serializers import AuthTokenSerializer
6+
from rest_framework.permissions import AllowAny
7+
from rest_framework.response import Response
8+
from rest_framework.views import APIView
9+
from project.accounts.models import User
10+
from project.accounts.serializers import (
11+
UserRegistrationSerializer, UserProfileSerializer, ResetPasswordSerializer
12+
)
13+
14+
15+
class TestView(TemplateView):
16+
"""
17+
This view should not be included in DRF Docs.
18+
"""
19+
template_name = "a_test.html"
20+
21+
22+
class LoginView(APIView):
23+
24+
throttle_classes = ()
25+
permission_classes = ()
26+
parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
27+
renderer_classes = (renderers.JSONRenderer,)
28+
serializer_class = AuthTokenSerializer
29+
30+
def post(self, request):
31+
serializer = self.serializer_class(data=request.data)
32+
serializer.is_valid(raise_exception=True)
33+
user = serializer.validated_data['user']
34+
token, created = Token.objects.get_or_create(user=user)
35+
return Response({'token': token.key})
36+
37+
38+
class UserRegistrationView(generics.CreateAPIView):
39+
40+
permission_classes = (AllowAny,)
41+
serializer_class = UserRegistrationSerializer
42+
43+
44+
class UserProfileView(generics.RetrieveUpdateAPIView):
45+
46+
serializer_class = UserProfileSerializer
47+
48+
def get_object(self):
49+
return self.request.user
50+
51+
52+
class PasswordResetView(APIView):
53+
54+
permission_classes = (AllowAny,)
55+
queryset = User.objects.all()
56+
57+
def get_object(self):
58+
email = self.request.data.get('email')
59+
obj = get_object_or_404(self.queryset, email=email)
60+
return obj
61+
62+
def post(self, request, *args, **kwargs):
63+
user = self.get_object()
64+
user.send_reset_password_email()
65+
return Response({}, status=status.HTTP_200_OK)
66+
67+
68+
class PasswordResetConfirmView(APIView):
69+
70+
permission_classes = (AllowAny,)
71+
serializer_class = ResetPasswordSerializer
72+
73+
def post(self, request, *args, **kwargs):
74+
serializer = ResetPasswordSerializer(data=request.data)
75+
if not serializer.is_valid():
76+
return Response({'errors': serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
77+
return Response({"msg": "Password updated successfully."}, status=status.HTTP_200_OK)

demo/project/organisations/__init__.py

Whitespace-only changes.

demo/project/organisations/models.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import uuid
2+
from django.db import models
3+
from project.accounts.models import User
4+
5+
6+
class Organisation(models.Model):
7+
8+
class Meta:
9+
verbose_name_plural = "Organisations"
10+
ordering = ['name']
11+
12+
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
13+
created = models.DateTimeField(auto_now_add=True)
14+
modified = models.DateTimeField(auto_now=True)
15+
16+
name = models.CharField(unique=True, max_length=100)
17+
slug = models.SlugField(unique=True)
18+
members = models.ManyToManyField(User, through='Membership', through_fields=('organisation', 'user'))
19+
20+
is_active = models.BooleanField(default=False)
21+
22+
def __str__(self):
23+
return self.name
24+
25+
26+
class Membership(models.Model):
27+
28+
class Meta:
29+
unique_together = ("organisation", "user")
30+
31+
MEMBER_ROLES = (
32+
("ADMIN", "Admin"),
33+
("USER", "User")
34+
)
35+
36+
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
37+
joined = models.DateTimeField(auto_now_add=True)
38+
39+
organisation = models.ForeignKey(Organisation)
40+
user = models.ForeignKey(User)
41+
role = models.CharField(choices=MEMBER_ROLES, max_length=20, default="USER")
42+
is_owner = models.BooleanField(default=False)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from rest_framework import serializers
2+
from project.organisations.models import Organisation, Membership
3+
from project.accounts.serializers import UserProfileSerializer
4+
5+
6+
class CreateOrganisationSerializer(serializers.ModelSerializer):
7+
8+
class Meta:
9+
model = Organisation
10+
fields = ('name', 'slug',)
11+
12+
13+
class OrganisationMembersSerializer(serializers.ModelSerializer):
14+
user = serializers.SerializerMethodField()
15+
16+
class Meta:
17+
model = Membership
18+
fields = ('joined', 'user', 'is_owner', 'role')
19+
20+
def get_user(self, obj):
21+
serializer = UserProfileSerializer(obj.user)
22+
return serializer.data
23+
24+
25+
class OrganisationDetailSerializer(serializers.ModelSerializer):
26+
27+
class Meta:
28+
model = Organisation
29+
fields = ('name', 'slug', 'is_active')

demo/project/organisations/urls.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from django.conf.urls import url
2+
from project.organisations import views
3+
4+
5+
urlpatterns = [
6+
7+
url(r'^create/$', view=views.CreateOrganisationView.as_view(), name="create"),
8+
url(r'^(?P<slug>[\w-]+)/members/$', view=views.OrganisationMembersView.as_view(), name="members"),
9+
url(r'^(?P<slug>[\w-]+)/leave/$', view=views.LeaveOrganisationView.as_view(), name="leave")
10+
11+
]

demo/project/organisations/views.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from rest_framework import generics, status
2+
from rest_framework.response import Response
3+
from project.organisations.models import Organisation, Membership
4+
from project.organisations.serializers import (
5+
CreateOrganisationSerializer, OrganisationMembersSerializer
6+
)
7+
8+
9+
class CreateOrganisationView(generics.CreateAPIView):
10+
11+
serializer_class = CreateOrganisationSerializer
12+
13+
14+
class OrganisationMembersView(generics.ListAPIView):
15+
16+
serializer_class = OrganisationMembersSerializer
17+
18+
def get_queryset(self):
19+
organisation = Organisation.objects.order_by('?').first()
20+
return Membership.objects.filter(organisation=organisation)
21+
22+
23+
class LeaveOrganisationView(generics.DestroyAPIView):
24+
25+
def get_object(self):
26+
return Membership.objects.order_by('?').first()
27+
28+
def delete(self, request, *args, **kwargs):
29+
instance = self.get_object()
30+
self.perform_destroy(instance)
31+
return Response(status=status.HTTP_204_NO_CONTENT)

0 commit comments

Comments
 (0)