-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #190
- Loading branch information
Showing
9 changed files
with
222 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Generated by Django 2.2.1 on 2019-05-19 13:34 | ||
|
||
from django.conf import settings | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
('beers', '0029_merge_20190519_1259'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='UserFavoriteBeer', | ||
fields=[ | ||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('notifications_enabled', models.BooleanField(default=False)), | ||
('beer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='favored_by_users', to='beers.Beer')), | ||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='favorite_beers', to=settings.AUTH_USER_MODEL)), | ||
], | ||
options={ | ||
'unique_together': {('beer', 'user')}, | ||
}, | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
from django.contrib import admin | ||
from django.contrib.auth.admin import UserAdmin | ||
|
||
from beers.admin import UserFavoriteBeerInline | ||
from .models import User | ||
|
||
|
||
@admin.register(User) | ||
class UserAdmin(UserAdmin): | ||
pass | ||
inlines = [UserFavoriteBeerInline] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,30 @@ | ||
|
||
from rest_framework import permissions | ||
|
||
|
||
class IsUserOrReadOnly(permissions.BasePermission): | ||
class UserPermission(permissions.BasePermission): | ||
""" | ||
Object-level permission to only allow owners of an object to edit it. | ||
Permissions for the user model: | ||
1. Admins can do everything | ||
2. Normal users can only read/write themselves | ||
""" | ||
|
||
def has_permission(self, request, view): | ||
if request.user.is_staff: | ||
return True | ||
if request.method == 'POST' and 'subscribe' in request.path: | ||
return True | ||
return request.method in permissions.SAFE_METHODS + ('PUT', 'PATCH') | ||
|
||
def has_object_permission(self, request, view, obj): | ||
|
||
if request.method in permissions.SAFE_METHODS: | ||
if request.user == obj: | ||
print('user matches') | ||
return True | ||
if request.user.is_staff: | ||
print('user is staff') | ||
return True | ||
|
||
return obj == request.user | ||
print('fall through') | ||
return request.method in permissions.SAFE_METHODS |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,77 @@ | ||
from rest_framework import viewsets, mixins | ||
from rest_framework.permissions import IsAdminUser | ||
from rest_framework import viewsets | ||
from rest_framework.decorators import action | ||
from rest_framework.generics import get_object_or_404 | ||
from rest_framework.response import Response | ||
from rest_framework.serializers import ValidationError | ||
|
||
from beers.models import UserFavoriteBeer | ||
from beers.serializers import UserFavoriteBeerSerializer | ||
from .models import User | ||
from .permissions import IsUserOrReadOnly | ||
from .permissions import UserPermission | ||
from .serializers import CreateUserSerializer, UserSerializer | ||
|
||
|
||
class UserViewSet(mixins.RetrieveModelMixin, | ||
mixins.UpdateModelMixin, | ||
viewsets.GenericViewSet): | ||
class UserViewSet(viewsets.ModelViewSet): | ||
""" | ||
Updates and retrieves user accounts | ||
""" | ||
queryset = User.objects.all() | ||
serializer_class = UserSerializer | ||
permission_classes = (IsUserOrReadOnly,) | ||
|
||
@action(detail=True, methods=['POST']) | ||
def subscribetobeer(self, request, pk): | ||
user = get_object_or_404(self.get_queryset(), id=pk) | ||
body = request.data.copy() | ||
body['user'] = user.id | ||
print(body) | ||
serializer = UserFavoriteBeerSerializer( | ||
data=body, context={'request': request}, | ||
) | ||
try: | ||
# validate it as if it's a new subscription | ||
serializer.is_valid(raise_exception=True) | ||
except ValidationError as exc: | ||
print('womp', exc) | ||
if 'beer' in request.data and 'notifications_enabled' in request.data: | ||
# is the user trying to update the existing subscription? | ||
try: | ||
fav = UserFavoriteBeer.objects.get( | ||
user=user, | ||
beer=request.data['beer'] | ||
) | ||
except UserFavoriteBeer.DoesNotExist: | ||
# nope, doesn't exist; raise the error | ||
raise exc | ||
# we do have a favorite instance | ||
serializer = UserFavoriteBeerSerializer( | ||
instance=fav, data=body, context={'request', request}, | ||
) | ||
if not serializer.is_valid(): | ||
# nope, still not valid | ||
raise exc | ||
serializer.save() | ||
return Response(serializer.data) | ||
# serializer is missing required fields | ||
raise exc | ||
serializer.save() | ||
return Response(serializer.data) | ||
|
||
@action(detail=True, methods=['POST']) | ||
def unsubscribefrombeer(self, request, pk): | ||
user = get_object_or_404(self.get_queryset(), id=pk) | ||
if 'beer' not in request.data: | ||
raise ValidationError({'beer': ['This field is required.']}) | ||
instance = get_object_or_404( | ||
UserFavoriteBeer.objects.all(), | ||
user=user, | ||
beer=request.data['beer'], | ||
) | ||
instance.delete() | ||
return Response('', status=204) | ||
|
||
def get_serializer_class(self): | ||
if self.request.method == 'POST': | ||
return CreateUserSerializer | ||
return super().get_serializer_class() | ||
|
||
class UserCreateViewSet(mixins.CreateModelMixin, | ||
viewsets.GenericViewSet): | ||
""" | ||
Creates user accounts | ||
""" | ||
queryset = User.objects.all() | ||
serializer_class = CreateUserSerializer | ||
permission_classes = (IsAdminUser,) | ||
serializer_class = UserSerializer | ||
permission_classes = (UserPermission, ) |