Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 53 additions & 10 deletions driftbase/api/players/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging

import marshmallow as ma
from drift.core.extensions.jwt import current_user
from drift.core.extensions.jwt import current_user, requires_roles
from drift.core.extensions.urlregistry import Endpoints
from flask import g, url_for, current_app
from flask.views import MethodView
Expand All @@ -18,7 +18,7 @@
summary,
tickets,
)
from driftbase.models.db import CorePlayer, MatchPlayer
from driftbase.models.db import CorePlayer, MatchPlayer, User
from driftbase.players import get_playergroup_ids
from driftbase.utils import url_player
from driftbase.schemas.players import PlayerSchema
Expand All @@ -29,9 +29,11 @@

endpoints = Endpoints()


def _get_shoutout():
return current_app.extensions["shoutout"]


def _get_db():
return g.db

Expand All @@ -40,17 +42,13 @@ class PlayersListArgs(ma.Schema):
class Meta:
strict = True

player_id = ma.fields.List(
ma.fields.Integer(), metadata=dict(description="Player ID's to filter for"
))
player_id = ma.fields.List(ma.fields.Integer(), metadata=dict(description="Player ID's to filter for"))
rows = ma.fields.Integer(metadata=dict(description="Number of rows to return, maximum of 100"))
player_group = ma.fields.String(
metadata=dict(description="The player group the players should belong to (see player-group api)"
))
key = ma.fields.List(ma.fields.String(), metadata=dict(description="Only return these columns"))
player_name = ma.fields.String(
metadata=dict(description="Player name to search for")
metadata=dict(description="The player group the players should belong to (see player-group api)")
)
key = ma.fields.List(ma.fields.String(), metadata=dict(description="Only return these columns"))
player_name = ma.fields.String(metadata=dict(description="Player name to search for"))


class PlayerPatchArgs(ma.Schema):
Expand Down Expand Up @@ -223,6 +221,51 @@ def _patch(self, player_id, args):
return my_player


@bp.route('/<int:player_id>/banned', endpoint='ban')
class PlayerAPI(MethodView):
class PlayerBanSchema(ma.Schema):
banned = ma.fields.Boolean()

@bp.response(http_client.OK, PlayerBanSchema())
def get(self, player_id):
"""
Query for ban status
"""
user = g.db.query(User).join(CorePlayer).filter(CorePlayer.player_id == player_id).first()
if user is None:
return abort(http_client.NOT_FOUND)
return dict(banned=(user.status == "banned"))

@requires_roles("game_service,service")
@bp.response(http_client.OK, PlayerBanSchema())
def post(self, player_id):
"""
Ban a player
"""
user = g.db.query(User).join(CorePlayer).filter(CorePlayer.player_id == player_id).first()
if user is None:
return abort(http_client.NOT_FOUND)
if user.status != "banned":
user.status = "banned"
g.db.commit()
current_app.shoutout.message("player:banned", player_id=player_id)
return dict(banned=True)

@requires_roles("game_service,service")
def delete(self, player_id):
"""
Lift a ban from a player
"""
user = g.db.query(User).join(CorePlayer).filter(CorePlayer.player_id == player_id).first()
if user is None:
return abort(http_client.NOT_FOUND)
if user.status == "banned":
user.status = "active"
g.db.commit()
current_app.shoutout.message("player:unbanned", player_id=player_id)
return dict(banned=False)


@endpoints.register
def endpoint_info(current_user):
template_player_gamestate_url = url_for("player_gamestate.entry", player_id=1337, namespace="namespace", _external=True)
Expand Down
16 changes: 11 additions & 5 deletions driftbase/auth/authenticate.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ def authenticate(username, password, automatic_account_creation=True, fallback_u
player_name = ""
if my_identity.user_id:
my_user = g.db.query(User).get(my_identity.user_id)
if my_user.status == "banned":
log.info(f"Logon identity is using a banned user {my_user.user_id}")
abort_unauthorized("User is banned")
if my_user.status != "active":
log.info(f"Logon identity is using an inactive user {my_user.user_id}, creating new one")
my_user = None
Expand Down Expand Up @@ -231,10 +234,11 @@ def authenticate(username, password, automatic_account_creation=True, fallback_u
log.info(f"Player for user {my_user.user_id} has been created with player_id {my_player.player_id}"
f" and uuid {my_player.player_uuid}")
if "player" in user_roles:
current_app.extensions.get('shoutout').message("player_created", user_id=user_id, username=username,
player_id=my_player.player_id,
player_identity=my_identity.identity_id,
player_uuid=my_player.player_uuid.hex)
message_data = dict(user_id=user_id, username=username, player_id=my_player.player_id,
player_identity=my_identity.identity_id, player_uuid=my_player.player_uuid.hex)
current_app.shoutout.message("player:player_created", **message_data)
# Remove this next line once all services have been updated to listen to the 'player' topic event
current_app.shoutout.message("player_created", **message_data)

if my_player:
if my_player.player_uuid is None:
Expand Down Expand Up @@ -273,7 +277,9 @@ def authenticate(username, password, automatic_account_creation=True, fallback_u
player_identities.append(
dict(identity_id=identity.identity_id, identity_type=identity.identity_type, name=identity.name))
message_data['identities'] = player_identities
current_app.extensions.get('shoutout').message("player_login", **message_data)
current_app.shoutout.message("player:player_login", **message_data)
# Remove this next line once all services have been updated to listen to the 'player' topic event
current_app.shoutout.message("player_login", **message_data)
return ret


Expand Down
29 changes: 29 additions & 0 deletions tests/players/test_players.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,32 @@ def test_players_keys(self):
r = self.get(url)
self.assertIsNotNone(r.json()[0]["player_id"])
self.assertIsNotNone(r.json()[0]["player_name"])


class PlayersBanTest(BaseCloudkitTest):
def test_get_ban_status(self):
self.auth("test_get_ban_status")
r = self.get(self.endpoints["my_player"] + "/banned").json()
self.assertFalse(r["banned"])

def test_ban_player(self):
self.auth("test_ban_player")
ban_url = self.endpoints["players"] + f"/{self.player_id}/banned"
# Test banning fails without game_service role
self.post(ban_url, expected_status_code=http_client.FORBIDDEN)
with self.as_game_service():
r = self.post(ban_url).json()
self.assertTrue(r["banned"])

def test_unban_player(self):
self.auth("test_unban_player")
ban_url = self.endpoints["players"] + f"/{self.player_id}/banned"
with self.as_game_service():
self.post(ban_url)
r = self.get(ban_url).json()
self.assertTrue(r["banned"])
# Test unbanning fails without game_service role
self.delete(ban_url, expected_status_code=http_client.FORBIDDEN)
with self.as_game_service():
r = self.delete(ban_url).json()
self.assertFalse(r["banned"])