Coverage for apps / profiles / models.py: 96%
23 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-12 10:49 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-12 10:49 +0000
1from django.conf import settings
2from django.db import models
5AVATAR_COLORS = [
6 "#d97850", # burnt orange
7 "#8fae6f", # sage green
8 "#6b9dad", # teal
9 "#9d80b8", # purple
10 "#d16b6b", # coral red
11 "#e6a05f", # amber
12 "#6bb8a5", # mint
13 "#c77a9e", # rose
14 "#7d9e6f", # olive
15 "#5b8abf", # steel blue
16]
19class Profile(models.Model):
20 """User profile for the recipe app."""
22 THEME_CHOICES = [
23 ("light", "Light"),
24 ("dark", "Dark"),
25 ]
27 UNIT_CHOICES = [
28 ("metric", "Metric"),
29 ("imperial", "Imperial"),
30 ]
32 user = models.OneToOneField(
33 settings.AUTH_USER_MODEL,
34 null=True,
35 blank=True,
36 on_delete=models.CASCADE,
37 related_name="profile",
38 )
39 name = models.CharField(max_length=100)
40 avatar_color = models.CharField(max_length=7) # Hex color
41 theme = models.CharField(max_length=10, choices=THEME_CHOICES, default="light")
42 unit_preference = models.CharField(max_length=10, choices=UNIT_CHOICES, default="metric")
43 unlimited_ai = models.BooleanField(default=False)
44 created_at = models.DateTimeField(auto_now_add=True)
45 updated_at = models.DateTimeField(auto_now=True)
47 def __str__(self):
48 return self.name
50 @classmethod
51 def next_avatar_color(cls):
52 """Return the next unused color from the palette, cycling if needed."""
53 used_colors = set(cls.objects.values_list("avatar_color", flat=True))
54 for color in AVATAR_COLORS:
55 if color not in used_colors:
56 return color
57 # All used - cycle based on count
58 return AVATAR_COLORS[cls.objects.count() % len(AVATAR_COLORS)]