Files
RosterChief/features/migrations/0001_initial.py
Bernard Siebens fed24bfee3 Add club-scoped feature flags on django-waffle
Adds a `features` app with a swappable waffle Flag (WAFFLE_FLAG_MODEL) that
gains a m2m to Club, so a feature can be rolled out club by club.

Two things worth calling out:

- `everyone` keeps waffle's contract of overriding *all* other targeting, so
  club targeting is only consulted when `everyone is None`. This keeps
  `everyone = False` usable as a hard kill-switch.
- m2m edits don't call save(), so waffle's per-flag cache would go stale when
  clubs are added or removed. A m2m_changed receiver flushes it from both
  directions, and get_flush_keys() drops the club-set key alongside waffle's own.

Note for future flag tests: waffle's cache is not rolled back with the test
transaction, so tests touching flags must clear it (see features/tests.py).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 16:42:22 +02:00

46 lines
3.2 KiB
Python

# Generated by Django 6.0.6 on 2026-07-13 14:29
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
('club', '0011_alter_club_slug'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Flag',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(help_text='The human/computer readable name.', max_length=100, unique=True, verbose_name='Name')),
('everyone', models.BooleanField(blank=True, help_text='Flip this flag on (Yes) or off (No) for everyone, overriding all other settings. Leave as Unknown to use normally.', null=True, verbose_name='Everyone')),
('percent', models.DecimalField(blank=True, decimal_places=1, help_text='A number between 0.0 and 99.9 to indicate a percentage of users for whom this flag will be active.', max_digits=3, null=True, verbose_name='Percent')),
('testing', models.BooleanField(default=False, help_text='Allow this flag to be set for a session for user testing', verbose_name='Testing')),
('superusers', models.BooleanField(default=True, help_text='Flag always active for superusers?', verbose_name='Superusers')),
('staff', models.BooleanField(default=False, help_text='Flag always active for staff?', verbose_name='Staff')),
('authenticated', models.BooleanField(default=False, help_text='Flag always active for authenticated users?', verbose_name='Authenticated')),
('languages', models.TextField(blank=True, default='', help_text='Activate this flag for users with one of these languages (comma-separated list)', verbose_name='Languages')),
('rollout', models.BooleanField(default=False, help_text='Activate roll-out mode?', verbose_name='Rollout')),
('note', models.TextField(blank=True, help_text='Note where this Flag is used.', verbose_name='Note')),
('created', models.DateTimeField(db_index=True, default=django.utils.timezone.now, help_text='Date when this Flag was created.', verbose_name='Created')),
('modified', models.DateTimeField(default=django.utils.timezone.now, help_text='Date when this Flag was last modified.', verbose_name='Modified')),
('clubs', models.ManyToManyField(blank=True, help_text='Activate this flag for these clubs.', related_name='flags', to='club.club', verbose_name='Clubs')),
('groups', models.ManyToManyField(blank=True, help_text='Activate this flag for these user groups.', to='auth.group', verbose_name='Groups')),
('users', models.ManyToManyField(blank=True, help_text='Activate this flag for these users.', to=settings.AUTH_USER_MODEL, verbose_name='Users')),
],
options={
'verbose_name': 'Flag',
'verbose_name_plural': 'Flags',
'abstract': False,
},
),
]