separate the logged in state from the online state for a character

I think we will need to distinguish in the database characters whose
players are online but not yet logged in, so start building for that now

Signed-off-by: Brian S. Stephan <bss@incorporeal.org>
This commit is contained in:
Brian S. Stephan 2024-05-10 14:39:41 -05:00
parent 34aa91ad9e
commit 7d0c8f3431
Signed by: bss
GPG Key ID: 3DE06D3180895FCB
4 changed files with 32 additions and 10 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 5.0.5 on 2024-05-10 21:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('idlerpg', '0002_character_player_must_have_unique_character_names'),
]
operations = [
migrations.AlterField(
model_name='character',
name='status',
field=models.CharField(choices=[('DISABLED', 'Disabled'), ('LOGGEDIN', 'Logged in'), ('OFFLINE', 'Offline'), ('ONLINE', 'Online')], default='OFFLINE', max_length=8),
),
]

View File

@ -66,7 +66,7 @@ class CharacterManager(models.Manager):
""" """
hashed_pass = make_password(password) hashed_pass = make_password(password)
character = self.create(name=name, game=game, password=hashed_pass, hostmask=hostmask, character = self.create(name=name, game=game, password=hashed_pass, hostmask=hostmask,
character_class=character_class, status=Character.CHARACTER_STATUS_ONLINE, character_class=character_class, status=Character.CHARACTER_STATUS_LOGGED_IN,
last_login=timezone.now()) last_login=timezone.now())
logger.info("%s::%s: created and logged in, next level @ %s", logger.info("%s::%s: created and logged in, next level @ %s",
character.game.name, character.name, character.next_level) character.game.name, character.name, character.next_level)
@ -77,12 +77,14 @@ class Character(models.Model):
"""A character in a game.""" """A character in a game."""
CHARACTER_STATUS_DISABLED = 'DISABLED' CHARACTER_STATUS_DISABLED = 'DISABLED'
CHARACTER_STATUS_LOGGED_IN = 'LOGGEDIN'
CHARACTER_STATUS_OFFLINE = 'OFFLINE' CHARACTER_STATUS_OFFLINE = 'OFFLINE'
CHARACTER_STATUS_ONLINE = 'ONLINE' CHARACTER_STATUS_ONLINE = 'ONLINE'
CHARACTER_STATUSES = { CHARACTER_STATUSES = {
CHARACTER_STATUS_DISABLED: "Disabled",
CHARACTER_STATUS_LOGGED_IN: "Logged in",
CHARACTER_STATUS_OFFLINE: "Offline", CHARACTER_STATUS_OFFLINE: "Offline",
CHARACTER_STATUS_ONLINE: "Online", CHARACTER_STATUS_ONLINE: "Online",
CHARACTER_STATUS_DISABLED: "Disabled",
} }
NICK_CHANGE_P = 30 NICK_CHANGE_P = 30
@ -153,7 +155,7 @@ class Character(models.Model):
# error if this is being called before it should be # error if this is being called before it should be
if self.next_level > timezone.now(): if self.next_level > timezone.now():
raise ValueError(f"character '{self.name}' can't level, it isn't yet {self.next_level}!") raise ValueError(f"character '{self.name}' can't level, it isn't yet {self.next_level}!")
if self.status != self.CHARACTER_STATUS_ONLINE: if self.status != self.CHARACTER_STATUS_LOGGED_IN:
raise ValueError(f"character '{self.name}' can't level, it isn't logged in!") raise ValueError(f"character '{self.name}' can't level, it isn't logged in!")
logger.debug("leveling up %s...", str(self)) logger.debug("leveling up %s...", str(self))
@ -169,15 +171,15 @@ class Character(models.Model):
Raises: Raises:
ValueError: if the provided password was incorrect, or the character isn't logged out ValueError: if the provided password was incorrect, or the character isn't logged out
""" """
if self.status != self.CHARACTER_STATUS_OFFLINE: if self.status != self.CHARACTER_STATUS_ONLINE:
raise ValueError(f"character '{self.name}' can't be logged in, isn't logged out!") raise ValueError(f"character '{self.name}' can't be logged in, isn't online!")
if not check_password(password, self.password): if not check_password(password, self.password):
raise ValueError(f"incorrect password for character '{self.name}'!") raise ValueError(f"incorrect password for character '{self.name}'!")
logger.debug("logging %s in...", str(self)) logger.debug("logging %s in...", str(self))
# we need to apply the time lost to the next level time # we need to apply the time lost to the next level time
self.next_level += timezone.now() - self.last_login self.next_level += timezone.now() - self.last_login
self.status = self.CHARACTER_STATUS_ONLINE self.status = self.CHARACTER_STATUS_LOGGED_IN
self.hostmask = hostmask self.hostmask = hostmask
logger.info("%s::%s: logged in, next level @ %s", self.game.name, self.name, self.next_level) logger.info("%s::%s: logged in, next level @ %s", self.game.name, self.name, self.next_level)
@ -187,7 +189,7 @@ class Character(models.Model):
Raises: Raises:
ValueError: the character isn't logged in ValueError: the character isn't logged in
""" """
if self.status != self.CHARACTER_STATUS_ONLINE: if self.status != self.CHARACTER_STATUS_LOGGED_IN:
raise ValueError(f"character '{self.name}' can't be logged out, isn't logged in!") raise ValueError(f"character '{self.name}' can't be logged out, isn't logged in!")
self.status = self.CHARACTER_STATUS_OFFLINE self.status = self.CHARACTER_STATUS_OFFLINE

View File

@ -49,7 +49,7 @@
"name": "bss", "name": "bss",
"password": "pbkdf2_sha256$720000$A941t4dL96zzqeldCFucrr$Pof137/IjT3p//ZR+iYNoBnGmYPG6jLbNqenwMA3hHY=", "password": "pbkdf2_sha256$720000$A941t4dL96zzqeldCFucrr$Pof137/IjT3p//ZR+iYNoBnGmYPG6jLbNqenwMA3hHY=",
"hostmask": "bss!bss@bss", "hostmask": "bss!bss@bss",
"status": "ONLINE", "status": "LOGGEDIN",
"character_class": "tester", "character_class": "tester",
"level": 0, "level": 0,
"next_level": "2024-05-05T05:20:45.437Z", "next_level": "2024-05-05T05:20:45.437Z",

View File

@ -56,11 +56,12 @@ class CharacterTest(TestCase):
char.log_out() char.log_out()
# logout has a penalty of its own, so this post-logout value is what will be altered # logout has a penalty of its own, so this post-logout value is what will be altered
old_next_level = char.next_level old_next_level = char.next_level
char.status = Character.CHARACTER_STATUS_ONLINE
with patch('django.utils.timezone.now', return_value=login_time): with patch('django.utils.timezone.now', return_value=login_time):
char.log_in('bss', 'bss!bss@test_log_in') char.log_in('bss', 'bss!bss@test_log_in')
assert char.next_level == old_next_level + timedelta(seconds=300) assert char.next_level == old_next_level + timedelta(seconds=300)
assert char.status == Character.CHARACTER_STATUS_ONLINE assert char.status == Character.CHARACTER_STATUS_LOGGED_IN
assert char.hostmask == 'bss!bss@test_log_in' assert char.hostmask == 'bss!bss@test_log_in'
def test_cant_log_in_when_already_online(self): def test_cant_log_in_when_already_online(self):
@ -73,6 +74,7 @@ class CharacterTest(TestCase):
"""Test that we can't log in the character if we don't have the right password.""" """Test that we can't log in the character if we don't have the right password."""
char = Character.objects.get(pk=1) char = Character.objects.get(pk=1)
char.log_out() char.log_out()
char.status = Character.CHARACTER_STATUS_ONLINE
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
char.log_in('bad pass', 'bss!bss@test_bad_password') char.log_in('bad pass', 'bss!bss@test_bad_password')
@ -147,7 +149,7 @@ class CharacterTest(TestCase):
with patch('django.utils.timezone.now', return_value=register_time): with patch('django.utils.timezone.now', return_value=register_time):
new_char = Character.objects.register('new', game, 'pass', 'bss!bss@test_register', 'unit tester') new_char = Character.objects.register('new', game, 'pass', 'bss!bss@test_register', 'unit tester')
assert new_char.status == Character.CHARACTER_STATUS_ONLINE assert new_char.status == Character.CHARACTER_STATUS_LOGGED_IN
assert new_char.next_level == register_time + timedelta(seconds=600) assert new_char.next_level == register_time + timedelta(seconds=600)
assert new_char.last_login == register_time assert new_char.last_login == register_time
assert new_char.password[0:13] == 'pbkdf2_sha256' assert new_char.password[0:13] == 'pbkdf2_sha256'