Skip to content

Commit

Permalink
feat(Admin): Handle granting admin role
Browse files Browse the repository at this point in the history
  • Loading branch information
TeoTN committed Dec 25, 2017
1 parent dc82461 commit 3b8fddc
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 163 deletions.
120 changes: 64 additions & 56 deletions api/permissions.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,64 @@
from rest_framework import permissions


class AccessOwnTeamOnly(permissions.BasePermission):
message = 'You cannot access team you don\'t belong to.'

def has_permission(self, request, view):
accessed_team = view.kwargs.get('team', None)
if not accessed_team:
return True
return request.user.member_set.filter(team__id=accessed_team).exists()

def has_object_permission(self, request, view, obj):
accessed_team = view.kwargs.get('team', None)
if not accessed_team or request.user.is_staff:
return True
return request.user.member_set.filter(team__id=accessed_team).exists()


class MemberPermissions(permissions.BasePermission):
message = 'You are not allowed to modify this member.'

def allow_accepting(self, request, view):
if request.method not in ['PATCH', 'DELETE']:
print('wrong method')
return False
member_id = view.kwargs.get('pk', None)
is_self = request.user.id == member_id
is_accepting = list(request.data.keys()) in [['is_accepted'], []]
if is_self or not is_accepting:
print('self or not is_accepting', is_self, is_accepting, list(request.data.keys()))
return False
request_teams = request.user.member_set.all().values_list('team__name', flat=True)
is_correct_team = view.get_object().team.name in request_teams
return is_correct_team

def has_permission(self, request, view):
if request.method == 'GET':
return True
team = view.kwargs.get('parent_lookup_team', None)
member_id = view.kwargs.get('pk', None)
is_admin = request.user.member_set.filter(team__id=team, is_team_admin=True).count() > 0
is_owner = request.user.member_set.filter(team__id=team, id=member_id).count() > 0
return is_admin or is_owner or self.allow_accepting(request, view)


class IsMatchOwner(permissions.BasePermission):
def has_permission(self, request, view):
accessed_team = view.kwargs.get('team', None)
if not accessed_team:
return True
return request.user.member_set.filter(team__id=accessed_team).exists()

def has_object_permission(self, request, view, obj):
owners = [u.pk for u in obj.users]
return request.user.member_set.filter(pk__in=owners).count() > 0
from rest_framework import permissions


class AccessOwnTeamOnly(permissions.BasePermission):
message = 'You cannot access team you don\'t belong to.'

def has_permission(self, request, view):
accessed_team = view.kwargs.get('team', None)
if not accessed_team:
return True
return request.user.member_set.filter(team__id=accessed_team).exists()

def has_object_permission(self, request, view, obj):
accessed_team = view.kwargs.get('team', None)
if not accessed_team or request.user.is_staff:
return True
return request.user.member_set.filter(team__id=accessed_team).exists()


class MemberPermissions(permissions.BasePermission):
message = 'You are not allowed to modify this member.'

def allow_accepting(self, request, view):
if request.method not in ['PATCH', 'DELETE']:
print('wrong method')
return False
member_id = view.kwargs.get('pk', None)
is_self = request.user.id == member_id
is_accepting = list(request.data.keys()) in [['is_accepted'], []]
if is_self or not is_accepting:
print('self or not is_accepting', is_self, is_accepting, list(request.data.keys()))
return False
request_teams = request.user.member_set.all().values_list('team__name', flat=True)
is_correct_team = view.get_object().team.name in request_teams
return is_correct_team

def has_permission(self, request, view):
if request.method == 'GET':
return True
team = view.kwargs.get('parent_lookup_team', None)
member_id = view.kwargs.get('pk', None)
is_admin = request.user.member_set.filter(team__id=team, is_team_admin=True).count() > 0
is_owner = request.user.member_set.filter(team__id=team, id=member_id).count() > 0
return is_admin or is_owner or self.allow_accepting(request, view)


class IsMatchOwner(permissions.BasePermission):
def has_permission(self, request, view):
accessed_team = view.kwargs.get('team', None)
if not accessed_team:
return True
return request.user.member_set.filter(team__id=accessed_team).exists()

def has_object_permission(self, request, view, obj):
owners = [u.pk for u in obj.users]
return request.user.member_set.filter(pk__in=owners).count() > 0


class IsAdmin(permissions.BasePermission):
def has_permission(self, request, view):
accessed_team = view.kwargs.get('team', None)
if not accessed_team:
return True
return request.user.member_set.filter(team__id=accessed_team).is_team_admin
170 changes: 85 additions & 85 deletions api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,85 +1,85 @@
from rest_framework import serializers
from tfoosball.models import Player, Member, Match, Team
from django.db.models import Func, F


class Round(Func):
function = 'ROUND'
template = '%(function)s(%(expressions)s, 0)'


class TeamSerializer(serializers.ModelSerializer):
class Meta:
model = Team
fields = ('id', 'name')


class PlayerSerializer(serializers.ModelSerializer):
class Meta:
model = Player
fields = ('id', 'email', 'first_name', 'last_name',)


class MemberSerializer(serializers.ModelSerializer):
exp_history = serializers.SerializerMethodField()
att_ratio = serializers.SerializerMethodField()
def_ratio = serializers.SerializerMethodField()
win_ratio = serializers.SerializerMethodField()
email = serializers.CharField(source='player.email', read_only=True)
first_name = serializers.CharField(source='player.first_name', read_only=True)
last_name = serializers.CharField(source='player.last_name', read_only=True)
whats_new_version = serializers.IntegerField(source='player.whats_new_version', read_only=True)
user_id = serializers.IntegerField(source='player.pk', read_only=True)

def get_att_ratio(self, obj):
return obj.att_ratio

def get_def_ratio(self, obj):
return obj.def_ratio

def get_win_ratio(self, obj):
return obj.win_ratio

def get_exp_history(self, obj):
return obj.exp_history.all() \
.values('date')\
.annotate(daily_avg=F('exp'))\
.annotate(amount=F('matches_played'))\
.order_by('date')

class Meta:
model = Member
fields = (
'id', 'username', 'email', 'first_name', 'last_name', 'exp', 'played', 'att_ratio', 'def_ratio',
'win_ratio', 'win_streak', 'lose_streak', 'curr_lose_streak', 'curr_win_streak', 'lowest_exp',
'highest_exp', 'exp_history', 'is_accepted', 'hidden', 'whats_new_version', 'user_id',
)


class MatchSerializer(serializers.ModelSerializer):
red_att = serializers.SlugRelatedField(slug_field='username', queryset=Member.objects.all())
red_def = serializers.SlugRelatedField(slug_field='username', queryset=Member.objects.all())
blue_att = serializers.SlugRelatedField(slug_field='username', queryset=Member.objects.all())
blue_def = serializers.SlugRelatedField(slug_field='username', queryset=Member.objects.all())
points = serializers.IntegerField(required=False)

def __init__(self, *args, **kwargs):
# Ensure that we use only members within team context, if present
ctx = kwargs.get('context', None)
if not ctx:
super(MatchSerializer, self).__init__(*args, **kwargs)
return
team_id = ctx['view'].kwargs.get('parent_lookup_team', None)
if team_id:
fields = ['red_att', 'red_def', 'blue_att', 'blue_def']
for field_name in fields:
field = self.fields[field_name]
field.queryset = field.queryset.filter(team_id=team_id)
super(MatchSerializer, self).__init__(*args, **kwargs)

class Meta:
model = Match
fields = (
'id', 'red_att', 'red_def', 'blue_att', 'blue_def', 'date',
'red_score', 'blue_score', 'points'
)
from rest_framework import serializers
from tfoosball.models import Player, Member, Match, Team
from django.db.models import Func, F


class Round(Func):
function = 'ROUND'
template = '%(function)s(%(expressions)s, 0)'


class TeamSerializer(serializers.ModelSerializer):
class Meta:
model = Team
fields = ('id', 'name')


class PlayerSerializer(serializers.ModelSerializer):
class Meta:
model = Player
fields = ('id', 'email', 'first_name', 'last_name',)


class MemberSerializer(serializers.ModelSerializer):
exp_history = serializers.SerializerMethodField()
att_ratio = serializers.SerializerMethodField()
def_ratio = serializers.SerializerMethodField()
win_ratio = serializers.SerializerMethodField()
email = serializers.CharField(source='player.email', read_only=True)
first_name = serializers.CharField(source='player.first_name', read_only=True)
last_name = serializers.CharField(source='player.last_name', read_only=True)
whats_new_version = serializers.IntegerField(source='player.whats_new_version', read_only=True)
user_id = serializers.IntegerField(source='player.pk', read_only=True)

def get_att_ratio(self, obj):
return obj.att_ratio

def get_def_ratio(self, obj):
return obj.def_ratio

def get_win_ratio(self, obj):
return obj.win_ratio

def get_exp_history(self, obj):
return obj.exp_history.all() \
.values('date')\
.annotate(daily_avg=F('exp'))\
.annotate(amount=F('matches_played'))\
.order_by('date')

class Meta:
model = Member
fields = (
'id', 'username', 'email', 'first_name', 'last_name', 'exp', 'played', 'att_ratio', 'def_ratio',
'win_ratio', 'win_streak', 'lose_streak', 'curr_lose_streak', 'curr_win_streak', 'lowest_exp',
'highest_exp', 'exp_history', 'is_accepted', 'hidden', 'whats_new_version', 'user_id', 'is_team_admin',
)


class MatchSerializer(serializers.ModelSerializer):
red_att = serializers.SlugRelatedField(slug_field='username', queryset=Member.objects.all())
red_def = serializers.SlugRelatedField(slug_field='username', queryset=Member.objects.all())
blue_att = serializers.SlugRelatedField(slug_field='username', queryset=Member.objects.all())
blue_def = serializers.SlugRelatedField(slug_field='username', queryset=Member.objects.all())
points = serializers.IntegerField(required=False)

def __init__(self, *args, **kwargs):
# Ensure that we use only members within team context, if present
ctx = kwargs.get('context', None)
if not ctx:
super(MatchSerializer, self).__init__(*args, **kwargs)
return
team_id = ctx['view'].kwargs.get('parent_lookup_team', None)
if team_id:
fields = ['red_att', 'red_def', 'blue_att', 'blue_def']
for field_name in fields:
field = self.fields[field_name]
field.queryset = field.queryset.filter(team_id=team_id)
super(MatchSerializer, self).__init__(*args, **kwargs)

class Meta:
model = Match
fields = (
'id', 'red_att', 'red_def', 'blue_att', 'blue_def', 'date',
'red_score', 'blue_score', 'points'
)
22 changes: 21 additions & 1 deletion api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from api.emailing import send_invitation
from tfoosball.models import Member, Match, Player, Team
from .serializers import MatchSerializer, MemberSerializer, TeamSerializer, PlayerSerializer
from .permissions import MemberPermissions, AccessOwnTeamOnly, IsMatchOwner
from .permissions import MemberPermissions, AccessOwnTeamOnly, IsMatchOwner, IsAdmin


def displayable(message):
Expand Down Expand Up @@ -155,6 +155,26 @@ def invite(self, request, pk=None):
status=status.HTTP_201_CREATED
)

@detail_route(methods=['post'], permission_classes=[IsAdmin])
def assign_admin(self, request, pk=None):
team = Team.objects.get(pk=pk)
username = request.data.get('username')
if not team or not username:
return Response(displayable('Incorrect request'), status=status.HTTP_400_BAD_REQUEST)
try:
member = team.member_set.get(username=username)
except Member.DoesNotExist:
return Response(
displayable(f'Unable to make {username} admin'),
status=status.HTTP_400_BAD_REQUEST
)
member.is_team_admin = True
member.save()
return Response(
displayable(f'Successfully granted {username} admin privileges'),
status=status.HTTP_200_OK
)


class MemberViewSet(NestedViewSetMixin, ModelViewSet):
serializer_class = MemberSerializer
Expand Down
42 changes: 21 additions & 21 deletions templates/callback.html
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static "styles.css" %}">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous">
</script>
<script>
const cb_params = {
'FRONTEND_CLIENT': '{{ FRONTEND_CLIENT }}',
}
</script>
<script src="{% static "callback.js" %}?v=2.1.0"></script>
</head>
<body>

</body>
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static "styles.css" %}">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous">
</script>
<script>
const cb_params = {
'FRONTEND_CLIENT': '{{ FRONTEND_CLIENT }}',
}
</script>
<script src="{% static "callback.js" %}?v=2.3.0"></script>
</head>
<body>

</body>
</html>

0 comments on commit 3b8fddc

Please sign in to comment.