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 #69 from davidcr01/3.2
Browse files Browse the repository at this point in the history
Release v3.2.0
  • Loading branch information
davidcr01 authored Jul 13, 2023
2 parents f62c4e8 + a5ffae2 commit 22a5798
Show file tree
Hide file tree
Showing 15 changed files with 483 additions and 87 deletions.
44 changes: 39 additions & 5 deletions Wordle+/django/djapi/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class PlayerViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows players to be viewed or edited.
"""
queryset = Player.objects.all().order_by('wins')
queryset = Player.objects.all()
serializer_class = PlayerSerializer

def get_serializer_class(self):
Expand Down Expand Up @@ -110,6 +110,19 @@ def destroy(self, request, *args, **kwargs):
# Delete the player
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)

@action(detail=False, methods=['get'])
def ranking(self, request):
filter_param = request.GET.get('filter')
limit = 15
queryset = Player.objects.all()

if filter_param:
queryset = queryset.order_by('-'+filter_param)[:limit]

serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)


class PlayerListAPIView(generics.ListAPIView):
queryset = Player.objects.all()
Expand Down Expand Up @@ -179,16 +192,17 @@ class ClassicWordleViewSet(viewsets.GenericViewSet):
"""
API endpoint that allows list, retrieve, and create operations for classic wordle games of players.
"""
permission_classes = [IsOwnerOrAdminPermission]
permission_classes = [permissions.IsAuthenticated]
queryset = ClassicWordle.objects.all()
serializer_class = ClassicWordleSerializer

def list(self, request):
player = getattr(request.user, 'player', None)
if not player:
return Response({'error': 'Player not found'}, status=404)

queryset = ClassicWordle.objects.filter(player=player).order_by('-date_played')

limit = 15
queryset = ClassicWordle.objects.filter(player=player).order_by('-date_played')[:limit]
serializer = ClassicWordleSerializer(queryset, many=True)
return Response(serializer.data)

Expand Down Expand Up @@ -443,6 +457,26 @@ def list(self, request, *args, **kwargs):
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)

def destroy(self, request, *args, **kwargs):
player = getattr(request.user, 'player', None)
friend_id = kwargs.get('pk')

if not player:
return Response({'error': 'Player not found'}, status=404)

try:
friend = Player.objects.get(id=friend_id)
except Player.DoesNotExist:
return Response({'error': 'Friend not found'}, status=404)

if not FriendList.objects.filter(Q(sender=player, receiver=friend) | Q(sender=friend, receiver=player)).exists():
return Response({'error': 'Player is not friends with this user'}, status=403)

# Delete the friend relationship
FriendList.objects.filter(Q(sender=player, receiver=friend) | Q(sender=friend, receiver=player)).delete()

return Response({'message': 'Friend relationship deleted successfully'}, status=204)

class FriendRequestViewSet(viewsets.ReadOnlyModelViewSet):
queryset = FriendRequest.objects.all()
serializer_class = FriendRequestSerializer
Expand Down Expand Up @@ -567,7 +601,7 @@ 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')[:limit]
queryset = Game.objects.filter(player2=player, winner=None, is_tournament_game=False).order_by('timestamp')[:limit]
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<ion-content>
<ion-list *ngIf="playerInfo">
<div class="popover-container">
<img src="../../assets/icon/wins-classic.png" alt="Victories Classic">
<ion-label class="popover-label">Wins</ion-label>
<ion-label class="popover-value">{{ playerInfo.wins }}</ion-label>
</div>
<div class="popover-container">
<img src="../../assets/icon/wins-pvp.png" alt="Victories PvP">
<ion-label class="popover-label">Wins PvP</ion-label>
<ion-label class="popover-value">{{ playerInfo.wins_pvp }}</ion-label>
</div>
<div class="popover-container">
<img src="../../assets/icon/wins-tournaments.png" alt="Victories Tournaments">
<ion-label class="popover-label">Tournaments</ion-label>
<ion-label class="popover-value">{{ playerInfo.wins_tournament }}</ion-label>
</div>
<div class="popover-container">
<img src="../../assets/icon/experience.png" alt="Experience">
<ion-label class="popover-label">XP</ion-label>
<ion-label class="popover-value">{{ playerInfo.xp }}</ion-label>
</div>
</ion-list>

</ion-content>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.popover-container {
display: flex;
align-items: center;
margin-bottom: 1vh;
}

.popover-container img {
width: 3vh;
height: 3vh;
margin-right: 2vw;
}

.popover-label {
font-weight: bold;
font-size: 4.5vw;
}

.popover-value {
margin-left: auto;
margin-right: 3vw;
font-size: 5.5vw;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';

import { PlayerInfoPopoverComponent } from './player-info-popover.component';

describe('PlayerInfoPopoverComponent', () => {
let component: PlayerInfoPopoverComponent;
let fixture: ComponentFixture<PlayerInfoPopoverComponent>;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ PlayerInfoPopoverComponent ],
imports: [IonicModule.forRoot()]
}).compileComponents();

fixture = TestBed.createComponent(PlayerInfoPopoverComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Component, OnInit, Input } from '@angular/core';
import { ApiService } from 'src/app/services/api.service';

@Component({
selector: 'app-player-info-popover',
templateUrl: './player-info-popover.component.html',
styleUrls: ['./player-info-popover.component.scss'],
})
export class PlayerInfoPopoverComponent implements OnInit {
@Input() playerId: string;
playerInfo: any;

constructor(private apiService: ApiService) {}

ngOnInit() {
this.loadPlayerData();
}

async loadPlayerData() {
if (this.playerId) {
(await this.apiService.getPlayerData(this.playerId)).subscribe(
(response: any) => {
this.playerInfo = response;
},
(error) => {
console.error('Error retrieving player data:', error);
}
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { WordsPopoverComponent } from 'src/app/components/words-popover/words-popover.component';
import { IonicModule } from '@ionic/angular';

import { PlayerInfoPopoverComponent } from 'src/app/components/player-info-popover/player-info-popover.component';
import { FriendlistPageRoutingModule } from './friendlist-routing.module';

import { FriendlistPage } from './friendlist.page';
Expand All @@ -15,6 +14,6 @@ import { FriendlistPage } from './friendlist.page';
IonicModule,
FriendlistPageRoutingModule
],
declarations: [FriendlistPage]
declarations: [FriendlistPage, PlayerInfoPopoverComponent]
})
export class FriendlistPageModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@
<ion-item>
<ion-icon name="information-circle" slot="start"></ion-icon>
<ion-label>View profile</ion-label>
<ion-button fill="clear" (click)="viewFriendInfo(friend.id)">
<ion-button fill="clear" (click)="viewFriendInfo($event, friend.id_player)">
<ion-icon name="information-circle-outline" slot="icon-only"></ion-icon>
</ion-button>
</ion-item>
<ion-item>
<ion-icon name="trash" slot="start"></ion-icon>
<ion-label>Delete friend</ion-label>
<ion-button fill="clear" (click)="removeFriend(friend.id)">
<ion-button fill="clear" (click)="confirmDeleteFriend(friend.id_player)">
<ion-icon name="close" color="danger" slot="icon-only"></ion-icon>
</ion-button>
</ion-item>
Expand Down
89 changes: 58 additions & 31 deletions Wordle+/ionic/ionic-app/src/app/pages/friendlist/friendlist.page.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Component, OnInit } from '@angular/core';
import { ApiService } from 'src/app/services/api.service';
import { ToastService } from 'src/app/services/toast.service';
import { PopoverController } from '@ionic/angular';
import { AlertController, PopoverController } from '@ionic/angular';
import { WordsPopoverComponent } from 'src/app/components/words-popover/words-popover.component';

import { PlayerInfoPopoverComponent } from 'src/app/components/player-info-popover/player-info-popover.component';

@Component({
selector: 'app-friendlist',
Expand All @@ -20,7 +20,7 @@ export class FriendlistPage implements OnInit {
showResults: boolean = false;

constructor(private apiService: ApiService, private toastService: ToastService,
private popoverController: PopoverController) {}
private popoverController: PopoverController, private alertController: AlertController) {}

ngOnInit() {
this.getAllPlayers();
Expand Down Expand Up @@ -124,12 +124,17 @@ export class FriendlistPage implements OnInit {
}
}

playWithFriend(friendId: number) {

}
async viewFriendInfo(event: any, friendId: number) {
const popover = await this.popoverController.create({
component: PlayerInfoPopoverComponent,
componentProps: {
playerId: friendId,
},
dismissOnSelect: true,
event: event
});

viewFriendInfo(friendId: number) {

await popover.present();
}

async acceptFriendRequest(requestId: number) {
Expand All @@ -148,32 +153,54 @@ export class FriendlistPage implements OnInit {
);
}

rejectFriendRequest(requestId: number) {
async rejectFriendRequest(requestId: number) {
(await this.apiService.rejectFriendRequest(requestId)).subscribe(
async (response) => {
console.log('Friend request rejected successfully', response);
this.loadFriendRequests();
},
async (error) => {
console.error('Error rejecting friend request:', error);
}
);
}


async removeFriend(friendId: number) {
/*
try {
await this.apiService.removeFriend(friendId);
await this.loadFriendList();
const toast = await this.toastController.create({
message: 'Friend removed successfully',
duration: 2000,
color: 'success'
});
toast.present();
} catch (error) {
console.error('Error removing friend:', error);
const toast = await this.toastController.create({
message: 'Error removing friend',
duration: 2000,
color: 'danger'
});
toast.present();
}
*/
async confirmDeleteFriend(friendId: number) {
const alert = await this.alertController.create({
header: 'Confirm',
message: 'Are you sure you want to delete this friend?',
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
},
{
text: 'Delete',
handler: () => {
this.deleteFriend(friendId);
},
},
],
});

await alert.present();
}


async deleteFriend(friendId: number) {
(await this.apiService.deleteFriend(friendId)).subscribe(
async (response) => {
console.log('Friend deleted successfully', response);
this.loadFriendList();
this.toastService.showToast('Friend was deleted succesfully.', 2000, 'top', 'success');
},
async (error) => {
console.error('Error accepting friend request:', error);
let message = "Error sending request";
this.toastService.showToast('Friend could not be deleted.', 2000, 'top', 'danger');
}
);
}
}

Loading

0 comments on commit 22a5798

Please sign in to comment.