2020-11-29 02:23:53 +05:00

253 lines
11 KiB
Python

from django.shortcuts import render
from rest_framework import permissions, status, generics
from rest_framework.response import Response
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
from rest_framework.decorators import api_view, permission_classes
from django.contrib.sites.shortcuts import get_current_site
from django.utils.encoding import force_bytes, force_text
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.template.loader import render_to_string
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.core.mail import EmailMultiAlternatives
from .serializers import UserRegisterSerializer, UserResetPasswordSerializer, UserPasswordSerializer, GameListSerializer, TeamSerializer
from django.utils.html import strip_tags
from django.contrib.auth.password_validation import validate_password
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter, SearchFilter
from .models import Game, Team, Gamer, Profile, InvitationToken
from django.utils import timezone
from hashlib import sha1
import six
import threading
class EmailTokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return(six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.is_active))
email_token_gen = EmailTokenGenerator()
password_token_gen = PasswordResetTokenGenerator()
def list_to_queryset(model_list):
if len(model_list) > 0:
return model_list[0].__class__.objects.filter(
pk__in=[obj.pk for obj in model_list])
else:
return []
class ListGamesAPIView(generics.ListAPIView):
serializer_class = GameListSerializer
permission_classes = [permissions.IsAuthenticated]
filter_backends = [SearchFilter, OrderingFilter, DjangoFilterBackend]
filterset_fields = ['co_op','max_gamers','active','average_time']
ordering_fields = ['max_gamers','active','average_time','name']
search_fields = ['name', 'description']
def get_queryset(self):
profile = Profile.objects.get(user = self.request.user)
if(self.kwargs['visited'] == '0'):
data = list(map(lambda team_i: team_i.game,filter(lambda ob:not Gamer.objects.filter(profile = profile, team = ob).exists(), Team.objects.all())))
else:
data = list(map(lambda team_i: team_i.game,filter(lambda ob:Gamer.objects.filter(profile = profile, team = ob).exists(), Team.objects.all())))
if(len(data)!=0):
return list_to_queryset(data)
else:
return Game.objects.none()
@api_view(['GET'])
@permission_classes([permissions.IsAuthenticated])
def SingleGameAPIView(request, slug):
game = Game.objects.filter(slug = slug)
if(game.exists()):
profile = Profile.objects.get(user = request.user)
game = game.first()
teams = Team.objects.filter(game = game)
team = []
for team_i in teams:
if(Gamer.objects.filter(profile = profile, team = team_i).exists()):
team = team_i
break
if(team):
serializer = TeamSerializer(team)
data = serializer.data
gamers = data['gamers']
can_start = False
invite_token = ''
if(not team.active):
if(team.captain == profile and (not game.co_op or len(gamers) == game.max_gamers) and not team.finished):
can_start = True
if(team.captain == profile and len(gamers) != game.max_gamers and not team.finished):
invite = InvitationToken.objects.filter(team = team)
if(invite.exists()):
invite = invite.first()
invite_token = invite.token
else:
pass
return Response({'ok':True, 'can_take_part':False, 'can_start':can_start, 'invite_token':invite_token, **data}, status = status.HTTP_200_OK)
else:
serializer = GameListSerializer(game)
data = serializer.data
return Response({'ok':True, 'can_take_part':True, **serializer.data}, status = status.HTTP_200_OK)
return Response({'ok':False, 'error':'Game does not exist'}, status = status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@permission_classes([permissions.IsAuthenticated])
def GameTakePartAPIView(request, slug):
game = Game.objects.filter(slug = slug)
if(game.exists()):
game = game.first()
profile = Profile.objects.get(user = request.user)
teams = Team.objects.filter(game = game)
team = []
for team_i in teams:
if(Gamer.objects.filter(profile = profile, team = team_i).exists()):
team = team_i
break
if(not team):
team = Team.objects.create(game = game, captain = profile)
if(game.co_op):
invite_token = sha1(bytes(f'{team.id}{game.id}{profile.id}{profile.user.username}','utf-8')).hexdigest()[:200]
InvitationToken.objects.create(team = team, token = invite_token)
gamer = Gamer.objects.create(team = team, profile = profile)
return Response({'ok':True}, status = status.HTTP_200_OK)
return Response({'ok':False, 'error':'You alredy take part in this game'}, status = status.HTTP_400_BAD_REQUEST)
return Response({'ok':False, 'error':'Game does not exist'}, status = status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@permission_classes([permissions.IsAuthenticated])
def JoinTeamAPIView(request, slug, token):
game = Game.objects.filter(slug = slug)
if(game.exists()):
invite = InvitationToken.objects.filter(token = token)
if(invite.exists()):
profile = Profile.objects.get(user = request.user)
invite = invite.first()
team = invite.team
serializer = TeamSerializer(team)
gamers = serializer.data['gamers']
if(len(gamers) < team.game.max_gamers):
Gamer.objects.create(team = team, profile = profile)
return Response({'ok':True},status = status.HTTP_200_OK)
return Response({'ok':False, 'error':'Game finished or team is full'}, status = status.HTTP_400_BAD_REQUEST)
return Response({'ok':False, 'error':'Invalid invite link'}, status = status.HTTP_400_BAD_REQUEST)
return Response({'ok':False, 'error':'Game does not exist'}, status = status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@permission_classes([permissions.IsAuthenticated])
def StartGameAPIView(request,slug):
game = Game.objects.filter(slug = slug)
if(game.exists()):
game = game.first()
profile = Profile.objects.get(user = request.user)
teams = Team.objects.filter(game = game, captain = profile)
team = []
for team_i in teams:
if(Gamer.objects.filter(profile = profile, team = team_i).exists()):
team = team_i
break
if(team):
if(team.captain == profile and not team.finished and not team.active):
team.is_active = True
team.start = timezone.now()
team.save()
return Response({'ok':True}, status = status.HTTP_200_OK)
return Response({'ok':False, 'error':'You are not a captain or game finished or game in progress'}, status = status.HTTP_400_BAD_REQUEST)
return Response({'ok':False, 'error':'You do not take part in game'}, status = status.HTTP_400_BAD_REQUEST)
return Response({'ok':False, 'error':'Game does not exist'}, status = status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@permission_classes([~permissions.IsAuthenticated])
def UserRegisterAPIView(request):
serializer = UserRegisterSerializer(data = request.data)
if(serializer.is_valid()):
data = serializer.validated_data
if(User.objects.filter(username = data['username']).exists() or User.objects.filter(email = data['email']).exists()):
return Response({'ok':False, 'error':'User already exists'}, status = status.HTTP_400_BAD_REQUEST)
try:
validate_password(data['password'])
except Exception as errors:
return Response({'ok':False, 'error':errors}, status = status.HTTP_400_BAD_REQUEST)
user = User.objects.create(username = data['username'], email = data['email'], is_active = False)
user.set_password(data['password'])
user.save()
domain = get_current_site(request).domain
mail_subject = 'Account activation'
message = render_to_string('email_activtion.html',{
'user':user,
'domain': domain,
'uidb64': urlsafe_base64_encode(force_bytes(user.pk)),
'token': email_token_gen.make_token(user),
})
message_task = threading.Thread(target = async_email_send, args=( mail_subject, message, [data['email']] ))
message_task.start()
return Response({'ok':True}, status = status.HTTP_200_OK)
return Response({'ok':False, 'error':serializer.errors}, status = status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@permission_classes([permissions.AllowAny])
def UserActivationAPIView(request, uidb64, token):
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.filter(id = uid)
if(user.exists()):
user = user.first()
if(email_token_gen.check_token(user, token)):
user.is_active = True
user.save()
return Response({'ok':True}, status = status.HTTP_200_OK)
return Response({'ok':False, 'error':'Invalid activation link'}, status = status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@permission_classes([~permissions.IsAuthenticated])
def UserResetPasswordRequestAPIView(request):
serializer = UserResetPasswordSerializer(data = request.data)
if(serializer.is_valid()):
data = serializer.validated_data
user = User.objects.filter(email = data['email'])
if(user.exists()):
user = user.first()
domain = get_current_site(request).domain
mail_subject = 'Password reset'
message = render_to_string('password_reset.html',{
'user':user,
'domain': domain,
'uidb64': urlsafe_base64_encode(force_bytes(user.pk)),
'token': password_token_gen.make_token(user),
})
message_task = threading.Thread(target = async_email_send, args=( mail_subject, message, [data['email']] ))
message_task.start()
return Response({'ok':True}, status = status.HTTP_200_OK)
return Response({'ok':False, 'error':'User does not exist'}, status = status.HTTP_400_BAD_REQUEST)
return Response({'ok':False, 'error':serializer.errors}, status = status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@permission_classes([~permissions.IsAuthenticated])
def UserResetPasswordAPIView(request, uidb64, token):
serializer = UserPasswordSerializer(data = request.data)
if(serializer.is_valid()):
data = serializer.validated_data
try:
validate_password(data['password'])
except Exception as errors:
return Response({'ok':False, 'error':errors}, status = status.HTTP_400_BAD_REQUEST)
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.filter(id = uid)
if(user.exists()):
user = user.first()
if(password_token_gen.check_token(user, token)):
user.set_password(data['password'])
user.save()
return Response({'ok':True}, status = status.HTTP_200_OK)
return Response({'ok':False, 'error':'Invalid password reset link'}, status = status.HTTP_400_BAD_REQUEST)
return Response({'ok':False, 'error':'User does not exist'}, status = status.HTTP_400_BAD_REQUEST)
return Response({'ok':False, 'error':serializer.errors}, status = status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@permission_classes([permissions.IsAuthenticated])
def UserLogoutAPIView(request):
Token.objects.get(user = request).delete()
return Response(status = status.HTTP_200_OK)
def async_email_send(mail_subject, message, to_email):
mail_to_send = EmailMultiAlternatives(mail_subject, strip_tags(message), to=to_email)
mail_to_send.attach_alternative(message, 'text/html')
mail_to_send.send()