add Game list, single game display, invites to teams

This commit is contained in:
TUTOR03 2020-11-28 23:48:34 +05:00
parent 642968c3a9
commit 91802c9ce1
9 changed files with 268 additions and 10 deletions

View File

@ -4,4 +4,7 @@ from . import models
admin.site.register(models.Profile) admin.site.register(models.Profile)
admin.site.register(models.CheckPoint) admin.site.register(models.CheckPoint)
admin.site.register(models.Game) admin.site.register(models.Game)
admin.site.register(models.InvitationToken)
admin.site.register(models.Gamer)
admin.site.register(models.Team)
# Register your models here. # Register your models here.

View File

@ -0,0 +1,50 @@
# Generated by Django 3.1.3 on 2020-11-28 16:20
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('back', '0003_auto_20201128_1939'),
]
operations = [
migrations.CreateModel(
name='Game_in_progress',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('active', models.BooleanField(default=False)),
('finished', models.BooleanField(default=False)),
('start', models.DateTimeField(blank=True, null=True)),
('end', models.DateTimeField(blank=True, null=True)),
],
),
migrations.AlterField(
model_name='game',
name='slug',
field=models.SlugField(blank=True, unique=True),
),
migrations.CreateModel(
name='Team',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('captain', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='back.profile')),
('game', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='back.game_in_progress')),
],
),
migrations.CreateModel(
name='Gamer',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='back.profile')),
('team', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='gamers', to='back.team')),
],
),
migrations.AddField(
model_name='game_in_progress',
name='game',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='back.game'),
),
]

View File

@ -0,0 +1,42 @@
# Generated by Django 3.1.3 on 2020-11-28 17:16
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('back', '0004_auto_20201128_2120'),
]
operations = [
migrations.AddField(
model_name='team',
name='active',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='team',
name='end',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AddField(
model_name='team',
name='finished',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='team',
name='start',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AlterField(
model_name='team',
name='game',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='back.game'),
),
migrations.DeleteModel(
name='Game_in_progress',
),
]

View File

@ -0,0 +1,22 @@
# Generated by Django 3.1.3 on 2020-11-28 18:17
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('back', '0005_auto_20201128_2216'),
]
operations = [
migrations.CreateModel(
name='InvitationToken',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('token', models.CharField(max_length=200)),
('team', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='back.team')),
],
),
]

View File

@ -37,6 +37,22 @@ class CheckPoint(models.Model):
start = models.BooleanField(default = False) start = models.BooleanField(default = False)
address = models.CharField(max_length = 200, blank = True, null = True) address = models.CharField(max_length = 200, blank = True, null = True)
class Team(models.Model):
game = models.ForeignKey(Game, on_delete= models.CASCADE, blank = False, null = False)
active = models.BooleanField(default = False)
finished = models.BooleanField(default = False)
start = models.DateTimeField(blank = True, null = True)
end = models.DateTimeField(blank = True, null = True)
captain = models.ForeignKey(Profile, on_delete = models.CASCADE, blank = True, null = True)
class InvitationToken(models.Model):
token = models.CharField(max_length = 200, blank = False, null = False)
team = models.ForeignKey(Team, on_delete = models.CASCADE, blank = False, null = False)
class Gamer(models.Model):
profile = models.ForeignKey(Profile, on_delete = models.CASCADE, blank = False, null = False)
team = models.ForeignKey(Team, on_delete = models.CASCADE, related_name = 'gamers', blank = False, null = False)
@receiver(post_save, sender = User) @receiver(post_save, sender = User)
def create_profile(sender, instance, created, **kwargs): def create_profile(sender, instance, created, **kwargs):
if(created): if(created):

View File

@ -1,6 +1,6 @@
from rest_framework import serializers from rest_framework import serializers
from django.contrib.auth.models import User from django.contrib.auth.models import User
from .models import Game from .models import Game, Team, Gamer
class GameListSerializer(serializers.ModelSerializer): class GameListSerializer(serializers.ModelSerializer):
class Meta: class Meta:
@ -17,6 +17,28 @@ class UserRegisterSerializer(serializers.ModelSerializer):
'email' 'email'
] ]
class TeamSerializer(serializers.ModelSerializer):
game = serializers.SerializerMethodField()
gamers = serializers.SerializerMethodField()
captain = serializers.SerializerMethodField()
class Meta:
model = Team
fields = [
'active',
'finished',
'start',
'end',
'captain',
'game',
'gamers',
]
def get_game(self, obj):
return(GameListSerializer(obj.game).data)
def get_gamers(self, obj):
return(list(map(lambda ob:ob.profile.user.username,Gamer.objects.filter(team = obj))))
def get_captain(self, obj):
return(obj.captain.user.username)
class UserResetPasswordSerializer(serializers.ModelSerializer): class UserResetPasswordSerializer(serializers.ModelSerializer):
email = serializers.EmailField(required=True) email = serializers.EmailField(required=True)
class Meta: class Meta:

View File

@ -4,8 +4,9 @@ from . import views
urlpatterns = [ urlpatterns = [
path('games', views.ListGamesAPIView.as_view(), name = 'ListGames'), path('games', views.ListGamesAPIView.as_view(), name = 'ListGames'),
path('game/<slug>', views.SingleGameAPIView.as_view(), name = 'SingleGame'), path('game/<slug>', views.SingleGameAPIView, name = 'SingleGame'),
# path('game/<slug>/take_part',), path('game/<slug>/take_part',views.GameTakePartAPIView, name = 'GameTakePartAPIView'),
path('game/<slug>/join_team/<token>',views.JoinTeamAPIView, name = 'JoinTeam'),
path('register', views.UserRegisterAPIView, name = 'UserRegister'), path('register', views.UserRegisterAPIView, name = 'UserRegister'),
path('login', obtain_auth_token, name = 'UserLogin'), path('login', obtain_auth_token, name = 'UserLogin'),
path('logout', views.UserLogoutAPIView, name = 'UserLogout'), path('logout', views.UserLogoutAPIView, name = 'UserLogout'),

View File

@ -10,12 +10,13 @@ from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.core.mail import EmailMultiAlternatives from django.core.mail import EmailMultiAlternatives
from .serializers import UserRegisterSerializer, UserResetPasswordSerializer, UserPasswordSerializer, GameListSerializer from .serializers import UserRegisterSerializer, UserResetPasswordSerializer, UserPasswordSerializer, GameListSerializer, TeamSerializer
from django.utils.html import strip_tags from django.utils.html import strip_tags
from django.contrib.auth.password_validation import validate_password from django.contrib.auth.password_validation import validate_password
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.filters import OrderingFilter, SearchFilter
from .models import Game from .models import Game, Team, Gamer, Profile, InvitationToken
from hashlib import sha1
import six import six
import threading import threading
@ -23,6 +24,12 @@ class EmailTokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp): def _make_hash_value(self, user, timestamp):
return(six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.is_active)) return(six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.is_active))
# class InviteTokenGenerator(PasswordResetTokenGenerator):
# def make_token(self, user,):
# return self._make_token_with_timestamp(user, self._num_seconds(self._now()))
# 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() email_token_gen = EmailTokenGenerator()
password_token_gen = PasswordResetTokenGenerator() password_token_gen = PasswordResetTokenGenerator()
@ -37,11 +44,80 @@ class ListGamesAPIView(generics.ListAPIView):
def get_queryset(self): def get_queryset(self):
return Game.objects.filter(active = True) return Game.objects.filter(active = True)
class SingleGameAPIView(generics.RetrieveAPIView): @api_view(['GET'])
serializer_class = GameListSerializer @permission_classes([permissions.IsAuthenticated])
permission_classes = [permissions.IsAuthenticated] def SingleGameAPIView(request, slug):
lookup_field = 'slug' game = Game.objects.filter(slug = slug)
queryset = Game.objects.all() 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(team.captain == profile and (not game.co_op or len(gamers) == game.max_gamers)):
can_start = True
if(team.captain == profile):
invite = InvitationToken.objects.filter(team = team)
if(invite.exists()):
invite = invite.first()
invite_token = invite.token
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, captain = profile)
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']) @api_view(['POST'])
@permission_classes([~permissions.IsAuthenticated]) @permission_classes([~permissions.IsAuthenticated])

26
backend/requirements.txt Normal file
View File

@ -0,0 +1,26 @@
asgiref==3.3.1
certifi==2020.11.8
cffi==1.14.4
chardet==3.0.4
cryptography==3.2.1
defusedxml==0.7.0rc1
Django==3.1.3
django-braces==1.14.0
django-filter==2.4.0
django-oauth-toolkit==1.3.3
django-rest-framework-social-oauth2==1.1.0
djangorestframework==3.12.2
idna==2.10
oauthlib==3.1.0
psycopg2==2.8.6
pycparser==2.20
PyJWT==1.7.1
python3-openid==3.2.0
pytz==2020.4
requests==2.25.0
requests-oauthlib==1.3.0
six==1.15.0
social-auth-app-django==4.0.0
social-auth-core==3.3.3
sqlparse==0.4.1
urllib3==1.26.2