72 lines
2.9 KiB
Python
72 lines
2.9 KiB
Python
from django.db import models
|
|
import hashlib # <-- import hashlib for computing md5
|
|
from cards.models import Card
|
|
from friend_codes.models import FriendCode
|
|
|
|
class TradeOffer(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
hash = models.CharField(max_length=8, editable=False)
|
|
initiated_by = models.ForeignKey("friend_codes.FriendCode", on_delete=models.PROTECT, related_name='initiated_by')
|
|
accepted_by = models.ForeignKey("friend_codes.FriendCode", on_delete=models.PROTECT, null=True, blank=True, related_name='accepted_by')
|
|
want_cards = models.ManyToManyField("cards.Card", related_name='trade_offers_want')
|
|
have_cards = models.ManyToManyField("cards.Card", related_name='trade_offers_have')
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
class State(models.TextChoices):
|
|
INITIATED = 'INITIATED', 'Initiated'
|
|
ACCEPTED = 'ACCEPTED', 'Accepted'
|
|
SENT = 'SENT', 'Sent'
|
|
RECEIVED = 'RECEIVED', 'Received'
|
|
|
|
state = models.CharField(
|
|
max_length=10,
|
|
choices=State.choices,
|
|
default=State.INITIATED,
|
|
)
|
|
|
|
def __str__(self):
|
|
return f"Want: {', '.join([x.name for x in self.want_cards.all()])} -> Have: {', '.join([x.name for x in self.have_cards.all()])}"
|
|
|
|
def update_state(self, new_state):
|
|
"""
|
|
Explicitly update the trade state to new_state if allowed.
|
|
|
|
Allowed transitions:
|
|
- INITIATED -> ACCEPTED
|
|
- ACCEPTED -> SENT
|
|
- SENT -> RECEIVED
|
|
|
|
Raises:
|
|
ValueError: If the new_state is not allowed.
|
|
"""
|
|
allowed_transitions = {
|
|
self.State.INITIATED: self.State.ACCEPTED,
|
|
self.State.ACCEPTED: self.State.SENT,
|
|
self.State.SENT: self.State.RECEIVED
|
|
}
|
|
|
|
# Check that new_state is one of the defined State choices
|
|
if new_state not in [choice[0] for choice in self.State.choices]:
|
|
raise ValueError(f"'{new_state}' is not a valid state.")
|
|
|
|
# If the current state is already final, no further transition is allowed.
|
|
if self.state not in allowed_transitions:
|
|
raise ValueError(f"No transitions allowed from the final state '{self.state}'.")
|
|
|
|
# Verify that the desired new_state is the valid transition for the current state.
|
|
if allowed_transitions[self.state] != new_state:
|
|
raise ValueError(f"Transition from {self.state} to {new_state} is not allowed.")
|
|
|
|
self.state = new_state
|
|
# Save all changes so that any in-memory modifications (like accepted_by) are persisted.
|
|
self.save() # Changed from self.save(update_fields=["state"])
|
|
|
|
def save(self, *args, **kwargs):
|
|
# Determine if the object is being created (i.e. it doesn't yet have a pk)
|
|
is_new = self.pk is None
|
|
super().save(*args, **kwargs)
|
|
# Once the object has a pk, compute and save the hash if it hasn't been set yet.
|
|
if is_new and not self.hash:
|
|
self.hash = hashlib.md5(str(self.id).encode('utf-8')).hexdigest()[:8]
|
|
super().save(update_fields=["hash"])
|