Skip to content

Commit

Permalink
Merge pull request #18 from Qwizi/0.0.21
Browse files Browse the repository at this point in the history
Added match config to match serializer and updated webhook url
  • Loading branch information
Qwizi committed Apr 21, 2024
2 parents f375d95 + cd7f4ba commit 9ed41ea
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 52 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "cs2-battle-bot-api"
version = "0.0.20"
version = "0.0.21"
description = ""
authors = ["Adrian Ciolek <ciolek.adrian@protonmail.com>"]
readme = "README.md"
Expand Down
5 changes: 3 additions & 2 deletions src/matches/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.db.models import Q
from prefix_id import PrefixIDField
from rest_framework.authtoken.models import Token
from rest_framework.reverse import reverse_lazy

from players.models import Team

Expand Down Expand Up @@ -70,7 +71,7 @@ def create_match(self, **kwargs):
server = kwargs.pop("server", None)
num_maps = kwargs.pop("num_maps", 1 if match_type == MatchType.BO1 else 3)
cvars = kwargs.pop("cvars", None)
webhook_url = kwargs.pop("webhook_url", None)
request = kwargs.pop("request", None)
players_list = team1.players.all() | team2.players.all()
player_per_team = len(players_list) / 2
players_per_team_rounded = math.ceil(player_per_team)
Expand All @@ -88,7 +89,7 @@ def create_match(self, **kwargs):
cvars=cvars,
)
match.maps.set(maps)
match.create_webhook_cvars(webhook_url=webhook_url)
match.create_webhook_cvars(webhook_url=str(reverse_lazy("match-webhook", args=[match.pk], request=request)))
match.save()
return match

Expand Down
8 changes: 7 additions & 1 deletion src/matches/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class MatchSerializer(serializers.ModelSerializer):
server = ServerSerializer(read_only=True, required=False, allow_null=True)
guild = GuildSerializer(read_only=True)
config_url = serializers.SerializerMethodField(method_name="get_config_url")
config = serializers.SerializerMethodField(method_name="get_config")

webhook_url = serializers.SerializerMethodField(method_name="get_webhook_url")
connect_command = serializers.CharField(
read_only=True, source="get_connect_command"
Expand All @@ -83,12 +85,15 @@ def get_config_url(self, obj) -> str:
return reverse_lazy("match-config", args=[obj.id], request=self.context["request"])

def get_webhook_url(self, obj) -> str:
return reverse_lazy("match-webhook", request=self.context["request"])
return reverse_lazy("match-webhook", args=[obj.id], request=self.context["request"])

def get_load_match_command(self, obj) -> str:
config_url = self.get_config_url(obj)
return f'{obj.load_match_command_name} "{config_url}" "{obj.api_key_header}" "{obj.get_author_token()}"'

def get_config(self, obj) -> dict:
return obj.get_config()

class Meta:
model = Match
fields = "__all__"
Expand All @@ -113,6 +118,7 @@ class MatchUpdateSerializer(serializers.Serializer):
guild_id = serializers.CharField(required=False)



class CreateMatchSerializer(serializers.Serializer):
discord_users_ids = serializers.ListField(child=serializers.CharField())
author_id = serializers.CharField(required=True)
Expand Down
6 changes: 3 additions & 3 deletions src/matches/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def match(teams_with_players, players, default_author, guild):
author=default_author.player.discord_user,
map_sides=["knife", "knife", "knife"],
guild=guild,
webhook_url=str(reverse_lazy("match-webhook", request=request)),
request=request
)
return new_match

Expand All @@ -86,14 +86,14 @@ def match_with_server(server, teams_with_players, default_author, guild):
factory = RequestFactory()

# Create a request
request = factory.get('/')
request2 = factory.get('/')
new_match = Match.objects.create_match(
team1=team1,
team2=team2,
author=default_author.player.discord_user,
map_sides=["knife", "knife", "knife"],
server=server,
guild=guild,
webhook_url=str(reverse_lazy("match-webhook", request=request)),
request=request2
)
return new_match
4 changes: 2 additions & 2 deletions src/matches/tests/test_matches_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def test_match_model(teams_with_players, default_author, with_server, match_type
clinch_series=clinch_series,
map_sides=["knife", "knife", "knife"],
server=server,
webhook_url=str(reverse_lazy("match-webhook", request=request)),
request=request
)
assert new_match.status == MatchStatus.CREATED
assert new_match.type == match_type
Expand Down Expand Up @@ -58,7 +58,7 @@ def test_match_model(teams_with_players, default_author, with_server, match_type
assert match_config["clinch_series"] is clinch_series
assert match_config["players_per_team"] == 5
assert match_config["cvars"] == new_match.cvars
assert match_config["cvars"]["matchzy_remote_log_url"] == reverse_lazy("match-webhook", request=request)
assert match_config["cvars"]["matchzy_remote_log_url"] == reverse_lazy("match-webhook", args=[new_match.pk], request=request)
assert match_config["cvars"]["matchzy_remote_log_header_key"] == new_match.api_key_header
assert match_config["cvars"]["matchzy_remote_log_header_value"] == new_match.get_author_token()

Expand Down
1 change: 0 additions & 1 deletion src/matches/tests/test_matches_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,6 @@ def test_match_recreate(client_with_api_key, match, match_with_server, with_serv
assert response.data["players_per_team"] == match_to_test.players_per_team
assert response.data["clinch_series"] == match_to_test.clinch_series
assert response.data["map_sides"] == match_to_test.map_sides
assert response.data["cvars"] == match_to_test.cvars
assert response.data["created_at"] is not None
assert response.data["updated_at"] is not None

Expand Down
42 changes: 21 additions & 21 deletions src/matches/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def create_match(request: Request) -> Response:
server=server,
cvars=cvars,
guild=guild,
webhook_url=str(reverse_lazy("match-webhook", request=request)),
request=request
)
new_match_serializer = MatchSerializer(new_match, context={"request": request})
return Response(new_match_serializer.data, status=201)
Expand Down Expand Up @@ -463,7 +463,7 @@ def publish_event(event: str, data: dict):
redis_client.publish(event, json.dumps(data))


def process_webhook(request: Request) -> Response:
def process_webhook(request: Request, pk) -> Response:
"""
Process a webhook event.
Expand All @@ -476,53 +476,53 @@ def process_webhook(request: Request) -> Response:
Response: Response object.
"""
match_event_serializer = MatchEventSerializer(data=request.data)
if not match_event_serializer.is_valid():
return Response(match_event_serializer.errors, status=400)
match_event_serializer.is_valid(raise_exception=True)
match_id = match_event_serializer.validated_data.get("matchid")
if match_id != pk:
return Response(
{"message": "Match ID in the request does not match the URL"},
status=400,
)
match: Match = get_object_or_404(Match, pk=match_id)
data = None
redis_event = None
match match_event_serializer.validated_data.get("event"):
case MatchEventEnum.SERIES_START:
series_start_serializer = MatchEventSeriesStartSerializer(data=request.data)
if not series_start_serializer.is_valid():
return Response(series_start_serializer.errors, status=400)
series_start_serializer.is_valid(raise_exception=True)
data = series_start_serializer.validated_data
match.status = MatchStatus.STARTED
match.save()
redis_event = f"event.{MatchEventEnum.SERIES_START.value}"
redis_event = f"event.{match.guild.guild_id}.{MatchEventEnum.SERIES_START.value}"
case MatchEventEnum.SERIES_END:
series_end_serializer = MatchEventSeriesEndSerializer(data=request.data)
if not series_end_serializer.is_valid():
return Response(series_end_serializer.errors, status=400)
series_end_serializer.is_valid(raise_exception=True)
data = series_end_serializer.validated_data
match.status = MatchStatus.FINISHED
match.save()
redis_event = f"event.{MatchEventEnum.SERIES_END.value}"
redis_event = f"event.{match.guild.guild_id}.{MatchEventEnum.SERIES_END.value}"

case MatchEventEnum.MAP_RESULT:
map_result_serializer = MatchEventMapResultSerializer(data=request.data)
if not map_result_serializer.is_valid():
return Response(map_result_serializer.errors, status=400)
map_result_serializer.is_valid(raise_exception=True)
data = map_result_serializer.validated_data
redis_event = f"event.{MatchEventEnum.MAP_RESULT.value}"
redis_event = f"event.{match.guild.guild_id}.{MatchEventEnum.MAP_RESULT.value}"
case MatchEventEnum.SIDE_PICKED:
redis_event = f"event.{MatchEventEnum.SIDE_PICKED.value}"
redis_event = f"event.{match.guild.guild_id}.{MatchEventEnum.SIDE_PICKED.value}"
case MatchEventEnum.MAP_PICKED:
redis_event = f"event.{MatchEventEnum.MAP_PICKED.value}"
redis_event = f"event.{match.guild.guild_id}.{MatchEventEnum.MAP_PICKED.value}"
case MatchEventEnum.MAP_VETOED:
redis_event = f"event.{MatchEventEnum.MAP_VETOED.value}"
redis_event = f"event.{match.guild.guild_id}.{MatchEventEnum.MAP_VETOED.value}"
case MatchEventEnum.ROUND_END:
data = request.data
redis_event = f"event.{MatchEventEnum.ROUND_END.value}"
redis_event = f"event.{match.guild.guild_id}.{MatchEventEnum.ROUND_END.value}"
case MatchEventEnum.GOING_LIVE:
going_live_serializer = MatchEventGoingLiveSerializer(data=request.data)
if not going_live_serializer.is_valid():
return Response(going_live_serializer.errors, status=400)
going_live_serializer.is_valid(raise_exception=True)
data = going_live_serializer.validated_data
match.status = MatchStatus.LIVE
match.save()
redis_event = f"event.{MatchEventEnum.GOING_LIVE.value}"
redis_event = f"event.{match.guild.guild_id}.{MatchEventEnum.GOING_LIVE.value}"

publish_event(redis_event, data)
print(f"Published event: {redis_event} with data: {data}")
Expand Down Expand Up @@ -597,7 +597,7 @@ def recreate_match(request, pk: int) -> Response:
author=match.author,
guild=match.guild,
server=match.server,
webhook_url=str(reverse_lazy("match-webhook", request=request)),
request=request
)
new_match_serializer = MatchSerializer(new_match, context={"request": request})
return Response(new_match_serializer.data, status=201)
6 changes: 3 additions & 3 deletions src/matches/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ def update(self, request, *args, **kwargs):
def load(self, request, pk=None):
return load_match(pk, request)

@action(detail=False, methods=["POST"], permission_classes=[IsAuthenticated])
def webhook(self, request):
return process_webhook(request)
@action(detail=True, methods=["POST"], permission_classes=[IsAuthenticated, IsAuthor], authentication_classes=[BearerTokenAuthentication])
def webhook(self, request, pk):
return process_webhook(request, pk)

@extend_schema(
request=MatchBanMapSerializer,
Expand Down
22 changes: 5 additions & 17 deletions src/servers/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,19 +124,6 @@ def test_create_server_with_guild(client_with_api_key, server_data, guild_data):
assert response.data["guild"] == guild.id


@pytest.mark.django_db
def test_get_servers_list_public_filter(client_with_api_key, server_data, guild_data):
server = Server.objects.create(**server_data)
guild = Guild.objects.create_guild(**guild_data)
server2 = Server.objects.create(ip="127.0.0.1", port=27016, name="Guild Server", password="changeme", rcon_password="test", is_public=False, guild=guild)
response = client_with_api_key.get(f"{API_ENDPOINT}?is_public=true")
assert response.status_code == 200
assert response.data["count"] == 1
assert Server.objects.count() == 2
assert response.data["results"][0]["is_public"] is True

# Ensure that the rcon_password is not exposed
assert "rcon_password" not in response.data["results"][0]


@pytest.mark.django_db
Expand All @@ -145,11 +132,12 @@ def test_get_servers_list_with_guild_filter(client_with_api_key, server_data, gu
guild = Guild.objects.create_guild(**guild_data)
server2 = Server.objects.create(ip="127.0.0.1", port=27016, name="Guild Server", password="changeme",
rcon_password="test", is_public=False, guild=guild)
response = client_with_api_key.get(f"{API_ENDPOINT}?guild={guild.id}")
server3 = Server.objects.create(ip="127.0.0.1", port=27016, name="Guild Server", password="changeme",
rcon_password="test", is_public=False)
response = client_with_api_key.get(f"{API_ENDPOINT}?guild_or_public={guild.id}")
assert response.status_code == 200
assert response.data["count"] == 1
assert Server.objects.count() == 2
assert response.data["results"][0]["guild"] == guild.id
assert response.data["count"] == 2
assert Server.objects.count() == 3

# Ensure that the rcon_password is not exposed
assert "rcon_password" not in response.data["results"][0]
Expand Down
25 changes: 24 additions & 1 deletion src/servers/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from django.db.models import Q
from django.http import HttpResponsePermanentRedirect
from django_filters import rest_framework as filters
from drf_spectacular.utils import extend_schema, OpenApiParameter
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny
Expand All @@ -11,10 +14,30 @@ class CustomSchemeRedirect(HttpResponsePermanentRedirect):
allowed_schemes = ["steam"]



class ServerViewSet(viewsets.ModelViewSet):
queryset = Server.objects.all().order_by("created_at")
serializer_class = ServerSerializer
filterset_fields = ["guild", "is_public"]

@extend_schema(
parameters=[
OpenApiParameter(
name="guild_or_public",
type=str,
)
]
)
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)

def get_queryset(self):
guild_or_public = self.request.query_params.get('guild_or_public')

if guild_or_public:
return Server.objects.filter(Q(is_public=True) | Q(guild__id=guild_or_public)).order_by("created_at")
else:
# No filters applied, return original queryset
return Server.objects.all().order_by("created_at")

def get_serializer_context(self):
context = super().get_serializer_context()
Expand Down

0 comments on commit 9ed41ea

Please sign in to comment.