add Game list, single game display, invites to teams
This commit is contained in:
parent
642968c3a9
commit
91802c9ce1
@ -4,4 +4,7 @@ from . import models
|
||||
admin.site.register(models.Profile)
|
||||
admin.site.register(models.CheckPoint)
|
||||
admin.site.register(models.Game)
|
||||
admin.site.register(models.InvitationToken)
|
||||
admin.site.register(models.Gamer)
|
||||
admin.site.register(models.Team)
|
||||
# Register your models here.
|
||||
|
50
backend/back/migrations/0004_auto_20201128_2120.py
Normal file
50
backend/back/migrations/0004_auto_20201128_2120.py
Normal 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'),
|
||||
),
|
||||
]
|
42
backend/back/migrations/0005_auto_20201128_2216.py
Normal file
42
backend/back/migrations/0005_auto_20201128_2216.py
Normal 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',
|
||||
),
|
||||
]
|
22
backend/back/migrations/0006_invitationtoken.py
Normal file
22
backend/back/migrations/0006_invitationtoken.py
Normal 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')),
|
||||
],
|
||||
),
|
||||
]
|
@ -37,6 +37,22 @@ class CheckPoint(models.Model):
|
||||
start = models.BooleanField(default = False)
|
||||
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)
|
||||
def create_profile(sender, instance, created, **kwargs):
|
||||
if(created):
|
||||
|
@ -1,6 +1,6 @@
|
||||
from rest_framework import serializers
|
||||
from django.contrib.auth.models import User
|
||||
from .models import Game
|
||||
from .models import Game, Team, Gamer
|
||||
|
||||
class GameListSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
@ -17,6 +17,28 @@ class UserRegisterSerializer(serializers.ModelSerializer):
|
||||
'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):
|
||||
email = serializers.EmailField(required=True)
|
||||
class Meta:
|
||||
|
@ -4,8 +4,9 @@ from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('games', views.ListGamesAPIView.as_view(), name = 'ListGames'),
|
||||
path('game/<slug>', views.SingleGameAPIView.as_view(), name = 'SingleGame'),
|
||||
# path('game/<slug>/take_part',),
|
||||
path('game/<slug>', views.SingleGameAPIView, name = 'SingleGame'),
|
||||
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('login', obtain_auth_token, name = 'UserLogin'),
|
||||
path('logout', views.UserLogoutAPIView, name = 'UserLogout'),
|
||||
|
@ -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.contrib.auth.tokens import PasswordResetTokenGenerator
|
||||
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.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
|
||||
from .models import Game, Team, Gamer, Profile, InvitationToken
|
||||
from hashlib import sha1
|
||||
import six
|
||||
import threading
|
||||
|
||||
@ -23,6 +24,12 @@ 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))
|
||||
|
||||
# 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()
|
||||
password_token_gen = PasswordResetTokenGenerator()
|
||||
|
||||
@ -37,11 +44,80 @@ class ListGamesAPIView(generics.ListAPIView):
|
||||
def get_queryset(self):
|
||||
return Game.objects.filter(active = True)
|
||||
|
||||
class SingleGameAPIView(generics.RetrieveAPIView):
|
||||
serializer_class = GameListSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
lookup_field = 'slug'
|
||||
queryset = Game.objects.all()
|
||||
@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(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'])
|
||||
@permission_classes([~permissions.IsAuthenticated])
|
||||
|
26
backend/requirements.txt
Normal file
26
backend/requirements.txt
Normal 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
|
Loading…
x
Reference in New Issue
Block a user