Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Flag mechanism #107

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions mockserver/tenants/migrations/0012_organization_feature_flags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 3.0.9 on 2021-01-31 00:19

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('tenants', '0011_project_slug_name'),
]

operations = [
migrations.CreateModel(
name='FeatureFlag',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(auto_now_add=True)),
('last_modified', models.DateTimeField(auto_now=True)),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='organization',
name='feature_flags',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='organization', to='tenants.FeatureFlag'),
),
]
34 changes: 34 additions & 0 deletions mockserver/tenants/migrations/0013_organization_profile_fix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Generated by Django 3.0.9 on 2021-01-31 01:50

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('tenants', '0012_organization_feature_flags'),
]

operations = [
migrations.AddField(
model_name='featureflag',
name='organization',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='featureflag', to='tenants.Organization'),
),
migrations.AddField(
model_name='organizationprofile',
name='organization',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='public_profile', to='tenants.Organization'),
),
migrations.AlterField(
model_name='organization',
name='feature_flags',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='deprecated_org', to='tenants.FeatureFlag'),
),
migrations.AlterField(
model_name='organization',
name='profile',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='deprecated_org', to='tenants.OrganizationProfile'),
),
]
31 changes: 31 additions & 0 deletions mockserver/tenants/migrations/0014_organization_data_migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Generated by Django 3.0.9 on 2021-01-31 04:36

from django.db import migrations


def forwards(apps, schema_editor):
Organization = apps.get_model('tenants', 'Organization')

for org in Organization.objects.all():
if org.profile is not None:
org.profile.organization = org
org.profile.save()

if org.feature_flags is not None:
org.feature_flags.organization = org
org.feature_flags.save()


def backwards(apps, schema_editor):
...


class Migration(migrations.Migration):

dependencies = [
('tenants', '0013_organization_profile_fix'),
]

operations = [
migrations.RunPython(forwards, backwards)
]
21 changes: 21 additions & 0 deletions mockserver/tenants/migrations/0015_organization_fields_remove.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 3.0.9 on 2021-01-31 04:55

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('tenants', '0014_organization_data_migration'),
]

operations = [
migrations.RemoveField(
model_name='organization',
name='feature_flags',
),
migrations.RemoveField(
model_name='organization',
name='profile',
),
]
24 changes: 24 additions & 0 deletions mockserver/tenants/migrations/0016_organization_rename_reverse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 3.0.9 on 2021-01-31 05:00

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('tenants', '0015_organization_fields_remove'),
]

operations = [
migrations.AlterField(
model_name='featureflag',
name='organization',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='feature_flags', to='tenants.Organization'),
),
migrations.AlterField(
model_name='organizationprofile',
name='organization',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='profile', to='tenants.Organization'),
),
]
33 changes: 24 additions & 9 deletions mockserver/tenants/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ class Meta:


class OrganizationProfile(models.Model):
organization = models.OneToOneField(
'tenants.Organization',
related_name="profile",
on_delete=models.CASCADE,
null=True
)

public_name = models.CharField(max_length=255)
description = models.TextField(null=True)
technologies = models.ManyToManyField(
Expand Down Expand Up @@ -94,20 +101,19 @@ class Organization(DateAwareModel):
through=OrganizationMembership,
blank=True
)
profile = models.OneToOneField(
'tenants.OrganizationProfile',
related_name='organization',
on_delete=models.CASCADE,
null=True
)

def save(self, **kwargs):
if not self.pk:
self.profile = OrganizationProfile.objects.create(
is_new = not self.pk
super(Organization, self).save(**kwargs)

if is_new:
OrganizationProfile.objects.create(
organization=self,
public_name=self.name
)
return super(Organization, self).save(**kwargs)
FeatureFlag.objects.create(
organization=self,
)

@property
def member_count(self):
Expand All @@ -121,6 +127,15 @@ def __str__(self):
return f"{self.name} ({self.uuid})"


class FeatureFlag(DateAwareModel):
organization = models.OneToOneField(
'tenants.Organization',
related_name="feature_flags",
on_delete=models.CASCADE,
null=True
)


class Tenant(DateAwareModel, User):
pass

Expand Down
30 changes: 24 additions & 6 deletions mockserver/tenants/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,36 @@
from common.tests.mixins import MockTestMixin
from tenants.models import (
OrganizationInvite,
OrganizationProfile
OrganizationProfile,
FeatureFlag
)


class OrganizationModelTestCase(MockTestMixin, TestCase):
def test_new_organization_creates_profile(self):
def test_organization_handles_profile(self):
organization = self.create_bare_minimum_organization()

self.assertIsNotNone(organization.profile)
self.assertEqual(OrganizationProfile.objects.count(), 1)
self.assertEqual(organization.profile.public_name, organization.name)
self.assertEqual(organization.profile.organization.pk, organization.pk)
with self.subTest("automatically creates profile"):
self.assertIsNotNone(organization.profile)
self.assertEqual(OrganizationProfile.objects.count(), 1)
self.assertEqual(organization.profile.public_name, organization.name)
self.assertEqual(organization.profile.organization.pk, organization.pk)
with self.subTest("automatically deletes profile"):
organization.delete()

self.assertEqual(OrganizationProfile.objects.count(), 0)


def test_organization_handles_feature_flags(self):
organization = self.create_bare_minimum_organization()

with self.subTest("automatically creates feature flag"):
self.assertIsNotNone(organization.feature_flags)
self.assertEqual(FeatureFlag.objects.count(), 1)
with self.subTest("automatically deletes feature flag"):
organization.delete()

self.assertEqual(FeatureFlag.objects.count(), 0)


class OrganizationInviteModelTestCase(MockTestMixin, TestCase):
Expand Down