Skip to content

Commit

Permalink
api endpoint for changing game mode
Browse files Browse the repository at this point in the history
  • Loading branch information
BrennanB committed Sep 12, 2024
1 parent 996dcbe commit 167cc7e
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 21 deletions.
1 change: 1 addition & 0 deletions change_match_game_mode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions ranked/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
path('<str:game_mode_code>/match/edit/', views.edit_match_result, name='edit_match_result'),
path('leaderboard/<str:game_mode_code>/', views.get_leaderboard, name='get_leaderboard'),
path('<str:game_mode_code>/players/', views.get_valid_players, name='get_valid_players'),
path('change-match-game-modes/', views.change_match_game_modes, name='change_match_game_modes'),
]
79 changes: 79 additions & 0 deletions ranked/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,3 +401,82 @@ def get_all_users(request: Request) -> Response:
} for user in users]

return Response(users_data)

@api_view(['POST'])
def change_match_game_modes(request: Request) -> Response:
"""
Changes the game mode of the most recent match for each specified game mode.
"""
if request.META.get('HTTP_X_API_KEY') != API_KEY:
return Response(status=401, data={
'error': 'Invalid API key.'
})

if 'matches' not in request.data or not isinstance(request.data['matches'], list):
return Response(status=400, data={'error': 'Invalid request format. Expected a list of matches.'})

results = []
for match_data in request.data['matches']:
if 'old_game_mode' not in match_data or 'new_game_mode' not in match_data:
results.append({'error': 'Invalid match data format. Expected old_game_mode and new_game_mode.'})
continue

try:
old_game_mode = GameMode.objects.get(short_code=match_data['old_game_mode'])
except GameMode.DoesNotExist:
results.append({'error': f"Game mode {match_data['old_game_mode']} does not exist."})
continue

try:
new_game_mode = GameMode.objects.get(short_code=match_data['new_game_mode'])
except GameMode.DoesNotExist:
results.append({'error': f"Game mode {match_data['new_game_mode']} does not exist."})
continue

match = Match.objects.filter(game_mode=old_game_mode).order_by('-match_number').first()
if not match:
results.append({'error': f"No matches found for {old_game_mode.short_code}."})
continue

red_players = match.red_alliance.all()
blue_players = match.blue_alliance.all()
red_player_elos = PlayerElo.objects.filter(player__in=red_players, game_mode=old_game_mode)
blue_player_elos = PlayerElo.objects.filter(player__in=blue_players, game_mode=old_game_mode)

red_elo_history = EloHistory.objects.filter(
match_number=match.match_number, player_elo__in=red_player_elos)
blue_elo_history = EloHistory.objects.filter(
match_number=match.match_number, player_elo__in=blue_player_elos)

revert_player_elos(match, red_elo_history, blue_elo_history)

match.game_mode = new_game_mode
match.time = timezone.now()
match.save()

red_player_elos = PlayerElo.objects.filter(player__in=red_players, game_mode=new_game_mode)
blue_player_elos = PlayerElo.objects.filter(player__in=blue_players, game_mode=new_game_mode)

red_elo_changes, blue_elo_changes = update_player_elos(
match, list(red_player_elos), list(blue_player_elos))

match_serializer = MatchSerializer(match)
red_player_elos_serializer = PlayerEloSerializer(red_player_elos, many=True)
blue_player_elos_serializer = PlayerEloSerializer(blue_player_elos, many=True)
red_display_names = [str(player) for player in red_players]
blue_display_names = [str(player) for player in blue_players]

results.append({
'match': match_serializer.data,
'red_player_elos': red_player_elos_serializer.data,
'blue_player_elos': blue_player_elos_serializer.data,
'red_display_names': red_display_names,
'blue_display_names': blue_display_names,
'red_elo_changes': red_elo_changes,
'blue_elo_changes': blue_elo_changes,
'old_game_mode': old_game_mode.short_code,
'new_game_mode': new_game_mode.short_code,
'status': 'success'
})

return Response(results)
46 changes: 25 additions & 21 deletions submit_matches.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,29 @@
load_dotenv()

API_KEY = os.getenv('SRC_API_TOKEN')
print(API_KEY)
API_BASE_URL = 'https://secondrobotics.org'

def get_valid_players(game_mode_code):
url = f"{API_BASE_URL}/api/ranked/{game_mode_code}/players/"
headers = {'X-API-KEY': API_KEY}

response = requests.get(url, headers=headers)
def get_all_users():
url = f"{API_BASE_URL}/api/ranked/all-users/"
response = requests.get(url)
if response.status_code == 200:
return response.json()
users = response.json()
# Filter out users with incorrect ID length
return [user for user in users if len(str(user['id'])) == 18]
else:
print(f"Failed to fetch valid players: {response.status_code}")
print(f"Failed to fetch users: {response.status_code}")
return None

def find_closest_match(name, valid_players):
def find_closest_match(name, all_users):
best_match = None
best_ratio = 0
for player in valid_players:
ratio_display = fuzz.ratio(name.lower(), player['display_name'].lower())
ratio_username = fuzz.ratio(name.lower(), player['username'].lower())
for user in all_users:
ratio_display = fuzz.ratio(name.lower(), user['display_name'].lower())
ratio_username = fuzz.ratio(name.lower(), user['username'].lower())
max_ratio = max(ratio_display, ratio_username)
if max_ratio > best_ratio:
best_ratio = max_ratio
best_match = player
best_match = user
return best_match, best_ratio

def validate_player_id(text):
Expand All @@ -47,9 +46,10 @@ def validate(self, document):
if not validate_player_id(text):
raise ValidationError(message='Please enter a valid 18-digit Discord ID')

def process_csv(file_path, valid_players):
def process_csv(file_path, all_users):
player_mappings = {}
matches = []
dummy_id = "000000000000000000" # Dummy player ID

with open(file_path, 'r') as csvfile:
reader = csv.reader(csvfile)
Expand All @@ -65,17 +65,21 @@ def process_csv(file_path, valid_players):
match.append(int(player))
player_mappings[player] = int(player)
else:
closest_match, ratio = find_closest_match(player, valid_players)
closest_match, ratio = find_closest_match(player, all_users)
if ratio == 100:
match.append(int(closest_match['id']))
player_mappings[player] = int(closest_match['id'])
else:
print(f"\nNo exact match found for '{player}'.")
print(f"Closest match: {closest_match['display_name']} (ID: {closest_match['id']})")
confirmation = prompt(f"Accept this match? (y/n): ").lower()
confirmation = prompt(f"Accept this match? (y/n/i for ignore): ").lower()
if confirmation == 'y':
match.append(int(closest_match['id']))
player_mappings[player] = int(closest_match['id'])
elif confirmation == 'i':
print(f"Ignoring player '{player}' and using dummy player.")
match.append(dummy_id)
player_mappings[player] = dummy_id
else:
manual_id = prompt("Enter the correct Discord ID: ", validator=PlayerIdValidator())
match.append(int(manual_id))
Expand Down Expand Up @@ -111,14 +115,14 @@ def submit_match(red_alliance, blue_alliance, red_score, blue_score, game_mode_c
csv_file_path = "matches.csv" # Replace with your CSV file path
game_mode_code = "CR3v3" # Replace with the appropriate game mode code

valid_players = get_valid_players(game_mode_code)
if not valid_players:
print("Failed to fetch valid players. Exiting.")
all_users = get_all_users()
if not all_users:
print("Failed to fetch users. Exiting.")
exit(1)

print(f"Fetched {len(valid_players)} valid players")
print(f"Fetched {len(all_users)} valid users")

matches = process_csv(csv_file_path, valid_players)
matches = process_csv(csv_file_path, all_users)

print("\nAll players processed. Ready to submit matches.")
confirmation = prompt("Do you want to submit these matches? (y/n): ").lower()
Expand Down

0 comments on commit 167cc7e

Please sign in to comment.