Skip to content
This repository has been archived by the owner on Jul 29, 2023. It is now read-only.

Commit

Permalink
Merge pull request #59 from davidcr01/3.0
Browse files Browse the repository at this point in the history
Release v3.0.0
  • Loading branch information
davidcr01 authored Jul 10, 2023
2 parents 2b35097 + f0730af commit 5705134
Show file tree
Hide file tree
Showing 42 changed files with 944 additions and 65 deletions.
7 changes: 3 additions & 4 deletions Wordle+/django/djangoproject/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,15 @@
}

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'djapi.token_expire.TokenExpirationMiddleware'

]
Expand Down
3 changes: 2 additions & 1 deletion Wordle+/django/djangoproject/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
router.register(r'api/groups', views.GroupViewSet)
router.register(r'api/classicwordles', views.ClassicWordleViewSet)
router.register(r'api/notifications', views.NotificationsViewSet)
router.register(r'api/games', views.GameViewSet)
router.register('api/friendlist', FriendListViewSet, basename='friendlist')
router.register('api/friendrequest', FriendRequestViewSet, basename='friendrequest')

Expand All @@ -46,4 +47,4 @@
path('api/list-players/', PlayerListAPIView.as_view(), name='player-list'),


] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
6 changes: 5 additions & 1 deletion Wordle+/django/djapi/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django import forms
from django.core.validators import MaxValueValidator

from .models import CustomUser, Player, StaffCode, ClassicWordle, Notification, Tournament, Participation, FriendList, FriendRequest
from .models import CustomUser, Player, StaffCode, ClassicWordle, Notification, Tournament, Participation, FriendList, FriendRequest, Game

class CustomUserAdmin(UserAdmin):
model = CustomUser
Expand Down Expand Up @@ -174,6 +174,10 @@ class FriendListAdmin(admin.ModelAdmin):
class FriendRequestAdmin(admin.ModelAdmin):
list_display = ('id', 'sender', 'receiver',)

class GameAdmin(admin.ModelAdmin):
list_display = ('id', 'player1', 'player2', 'winner', 'word',)

admin.site.register(Game, GameAdmin)
admin.site.register(FriendRequest, FriendRequestAdmin)
admin.site.register(FriendList, FriendListAdmin)
admin.site.register(Participation, ParticipationAdmin)
Expand Down
18 changes: 17 additions & 1 deletion Wordle+/django/djapi/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,23 @@ def clean(self):

def __str__(self):
return f"{self.sender.user.username} - {self.receiver.user.username}"


class Game(models.Model):
player1 = models.ForeignKey(Player, on_delete=models.CASCADE, related_name='player1_wordle')
player2 = models.ForeignKey(Player, on_delete=models.CASCADE, related_name='player2_wordle')
word = models.CharField(max_length=255)
player1_time = models.PositiveIntegerField(default=0)
player1_attempts = models.PositiveIntegerField(default=0)
player1_xp = models.PositiveIntegerField(default=0)
player2_time = models.PositiveIntegerField(default=0)
player2_attempts = models.PositiveIntegerField(default=0)
player2_xp = models.PositiveIntegerField(default=0)
winner = models.ForeignKey(Player, on_delete=models.SET_NULL, null=True, blank=True, related_name='winner')
timestamp = models.DateTimeField(auto_now_add=True)

def __str__(self):
return f"{self.player1.user.username} - {self.player2.user.username}"

# Method to add the 'Staff' group automatically when creating an administrator
@receiver(post_save, sender=CustomUser)
def assign_permissions(sender, instance, created, **kwargs):
Expand Down
30 changes: 29 additions & 1 deletion Wordle+/django/djapi/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.contrib.auth.models import Group
from .models import CustomUser, Player, StaffCode, ClassicWordle, Notification, Tournament, Participation, FriendList, FriendRequest
from .models import CustomUser, Player, StaffCode, ClassicWordle, Notification, Tournament, Participation, FriendList, FriendRequest, Game
from rest_framework import serializers
from django.contrib.auth.hashers import make_password

Expand Down Expand Up @@ -167,6 +167,34 @@ class Meta:
def get_sender(self, obj):
return {'username': obj.sender.user.username, 'id_player': obj.sender.user.player.id}

class GameDetailSerializer(serializers.ModelSerializer):
player1 = serializers.SerializerMethodField()
player2 = serializers.SerializerMethodField()

class Meta:
model = Game
fields = ['id', 'player1', 'player2', 'player1_time', 'player2_time', 'player1_xp',
'player2_xp', 'timestamp', 'word', 'player1_attempts', 'player2_attempts',
'winner']

def get_player1(self, obj):
return obj.player1.user.username

def get_player2(self, obj):
return obj.player2.user.username


class GameCreateSerializer(serializers.ModelSerializer):
player2 = serializers.SerializerMethodField()
class Meta:
model = Game
fields = ['id', 'player2', 'player1_time', 'player2_time', 'player1_xp',
'player2_xp', 'timestamp', 'word', 'player1_attempts', 'player2_attempts',
'winner']

def get_player2(self, obj):
return obj.player2.user.username

class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Group
Expand Down
139 changes: 137 additions & 2 deletions Wordle+/django/djapi/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ def create(self, request, *args, **kwargs):

serializer = FriendRequestSerializer(friend_request)
return Response(serializer.data, status=status.HTTP_201_CREATED)

@action(detail=True, methods=['post'])
def accept(self, request, *args, **kwargs):
instance = self.get_object()
Expand Down Expand Up @@ -456,4 +456,139 @@ def reject(self, request, *args, **kwargs):
return Response({'error': 'Permission denied'}, status=403)

instance.delete()
return Response({'message': 'Friend request rejected'}, status=200)
return Response({'message': 'Friend request rejected'}, status=200)

class GameViewSet(viewsets.ModelViewSet):
queryset = Game.objects.all()
serializer_class = GameCreateSerializer
permission_classes = [permissions.IsAuthenticated]
http_method_names = ['get', 'post', 'patch']

def get_serializer_class(self):
if self.action in ['list', 'retrieve', 'completed_games', 'pending_games']:
return GameDetailSerializer
elif self.action in ['create', 'partial_update']:
return GameCreateSerializer
return super().get_serializer_class()

# Completed games are those which the winner is not null
@action(detail=False, methods=['get'])
def completed_games(self, request):
player = getattr(request.user, 'player', None)
if not player:
return Response({'error': 'Player not found'}, status=404)

queryset = Game.objects.filter(Q(player1=player) | Q(player2=player), ~Q(winner=None)).order_by('timestamp')
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)

# Pending games are those which the winner is null and the player is the receiver (player2)
@action(detail=False, methods=['get'])
def pending_games(self, request):
player = getattr(request.user, 'player', None)
if not player:
return Response({'error': 'Player not found'}, status=404)
queryset = Game.objects.filter(player2=player, winner=None).order_by('timestamp')
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)

def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
player = getattr(request.user, 'player', None)
if not player:
return Response({'error': 'Player not found'}, status=404)

if player not in [instance.player1, instance.player2]:
return Response({'error': 'You can not access to this game.'}, status=403)
if instance.winner is not None:
return Response({'error': 'This game is already completed and cannot be modified.'}, status=403)

serializer = self.get_serializer(instance)
data = serializer.data

return Response(data)

def create(self, request, *args, **kwargs):
player1 = getattr(request.user, 'player', None)
if not player1:
return Response({'error': 'Player1 not found'}, status=404)
player2_id = request.data.get('player2')

if not player2_id:
return Response({'error': 'player2 parameter is required'}, status=400)

try:
player2 = Player.objects.get(id=player2_id)
except Player.DoesNotExist:
return Response({'error': 'Player2 not found'}, status=status.HTTP_404_NOT_FOUND)

allowed_fields = ['player2', 'player1_xp', 'player1_time', 'player1_attempts', 'word']
data = {key: request.data.get(key) for key in allowed_fields}

if 'winner' in data:
return Response({'error': 'The "winner" field cannot be modified.'}, status=400)


serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)

# Increment player XP
player1.xp += serializer.validated_data['player1_xp']
player1.save()

serializer.save(player1=player1, player2=player2)

# Create notification to the guest player
Notification.objects.create(
player=player2,
text=f"You have been challenged by {player1.user.username}. Let's play!",
link=''
)

return Response(serializer.data, status=201)

def partial_update(self, request, *args, **kwargs):
instance = self.get_object()
player = request.user.player

if instance.player2 != player:
return Response({'error': 'You do not have permission to update this game.'}, status=403)
if instance.winner is not None:
return Response({'error': 'This game is already completed and cannot be modified.'}, status=400)

allowed_fields = ['player2_xp', 'player2_time', 'player2_attempts']
data = {key: request.data.get(key) for key in allowed_fields}

if 'winner' in data:
return Response({'error': 'The "winner" field cannot be modified.'}, status=400)

player2_xp = request.data.get('player2_xp')
player1_xp = instance.player1_xp
player2_time = request.data.get('player2_time')
player1_time = instance.player1_time

if player2_xp is not None:
player1_xp = instance.player1_xp
if player2_xp > player1_xp:
instance.winner = instance.player2
instance.winner.wins_pvp += 1
instance.winner.save()
elif player2_xp < player1_xp:
instance.winner = instance.player1
instance.winner.wins_pvp += 1
instance.winner.save()
else:
if player2_time <= player1_time:
instance.winner = instance.player2
instance.winner.wins_pvp += 1
instance.winner.save()
else:
instance.winner = instance.player1
instance.winner.wins_pvp += 1
instance.winner.save()

serializer = self.get_serializer(instance, data=data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()

return Response({'winner': instance.winner.user.username})
19 changes: 15 additions & 4 deletions Wordle+/ionic/ionic-app/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,21 @@ const routes: Routes = [
loadChildren: () => import('./pages/friendlist/friendlist.module').then( m => m.FriendlistPageModule),
canActivate: [AuthGuard]
},




{
path: 'create-game',
loadChildren: () => import('./pages/create-game/create-game.module').then( m => m.CreateGamePageModule),
canActivate: [AuthGuard]
},
{
path: 'respond-game',
loadChildren: () => import('./pages/respond-game/respond-game.module').then( m => m.RespondGamePageModule),
canActivate: [AuthGuard]
},
{
path: 'history',
loadChildren: () => import('./pages/history/history.module').then( m => m.HistoryPageModule),
canActivate: [AuthGuard]
},

];
@NgModule({
Expand Down
Loading

0 comments on commit 5705134

Please sign in to comment.