unique constraint for only one hostmask enabled at a time

this replaces the need for a game+hostmask unique constraint, with this
change, a player can only have one active character they're playing
with anyway, regardless of how many games there are

Signed-off-by: Brian S. Stephan <bss@incorporeal.org>
This commit is contained in:
Brian S. Stephan 2024-05-14 11:13:13 -05:00
parent d0531bff53
commit 2ad79285b3
Signed by: bss
GPG Key ID: 3DE06D3180895FCB
3 changed files with 52 additions and 1 deletions

View File

@ -0,0 +1,26 @@
# Generated by Django 5.0.5 on 2024-05-14 16:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('idlerpg', '0006_alter_character_status'),
]
operations = [
migrations.RemoveConstraint(
model_name='character',
name='one_player_character_per_game',
),
migrations.AddField(
model_name='character',
name='enabled',
field=models.BooleanField(default=True),
),
migrations.AddConstraint(
model_name='character',
constraint=models.UniqueConstraint(condition=models.Q(('enabled', True)), fields=('hostmask',), name='one_enabled_character_at_a_time'),
),
]

View File

@ -95,6 +95,7 @@ class Character(models.Model):
password = models.CharField(max_length=256)
hostmask = models.CharField(max_length=256)
status = models.CharField(max_length=8, choices=CHARACTER_STATUSES, default='OFFLINE')
enabled = models.BooleanField(default=True)
character_class = models.CharField(max_length=30)
level = models.PositiveIntegerField(default=0)
@ -119,7 +120,8 @@ class Character(models.Model):
"""Options for the Character and its objects."""
constraints = [
models.UniqueConstraint("game", "hostmask", name="one_player_character_per_game"),
models.UniqueConstraint(fields=['hostmask'], condition=models.Q(enabled=True),
name='one_enabled_character_at_a_time'),
]
def __str__(self):

View File

@ -7,6 +7,8 @@ import logging
from datetime import timedelta
from unittest.mock import patch
from django.db import transaction
from django.db.utils import IntegrityError
from django.test import TestCase
from django.utils import timezone
@ -152,6 +154,27 @@ class CharacterTest(TestCase):
assert new_char.last_login == register_time
assert new_char.password[0:13] == 'pbkdf2_sha256'
def test_cant_register_twice(self):
"""Test that we get a unique constraint error if we try to make a second enabled character."""
game = Game.objects.get(pk=1)
register_time = timezone.now()
with patch('django.utils.timezone.now', return_value=register_time):
new_char = Character.objects.register('new1', game, 'pass', 'bss!bss@test_double_register', 'unit tester')
with self.assertRaises(IntegrityError):
with transaction.atomic():
Character.objects.register('new2', game, 'pass', 'bss!bss@test_double_register', 'unit tester')
# try again with the first character un-enabled
new_char.enabled = False
new_char.save()
register_time = timezone.now()
with patch('django.utils.timezone.now', return_value=register_time):
newer_char = Character.objects.register('new2', game, 'pass', 'bss!bss@test_double_register', 'unit tester')
assert new_char.hostmask == newer_char.hostmask
def test_level_up(self):
"""Test the level up functionality."""
char = Character.objects.get(pk=1)