diff --git a/castellum_core/Makefile b/castellum_core/Makefile
index 0b72682d655df77e86254d3962939800d44d61fa..2b7bd51cd4e78484679d49202e462edfb69bda8e 100644
--- a/castellum_core/Makefile
+++ b/castellum_core/Makefile
@@ -10,6 +10,7 @@ bootstrap: install migrate createsuperuser castellum_core/locale/de/LC_MESSAGES/
migrate:
$(MANAGEPY) migrate
+ $(MANAGEPY) migrate --database=subject_management
makemigrations:
$(MANAGEPY) makemigrations
diff --git a/castellum_core/castellum_core/castellum_core/settings/default.py b/castellum_core/castellum_core/castellum_core/settings/default.py
index 4fa505e84d94036c7817e5df65061137a3b62eb9..461a27377044001c7aad8d677cebb8db5aeb4eaf 100644
--- a/castellum_core/castellum_core/castellum_core/settings/default.py
+++ b/castellum_core/castellum_core/castellum_core/settings/default.py
@@ -21,6 +21,7 @@ INSTALLED_APPS = [
'bootstrap4',
'castellum_auth.apps.CastellumAuthConfig',
+ 'subject_management',
]
MIDDLEWARE = [
@@ -39,6 +40,7 @@ MIDDLEWARE = [
ROOT_URLCONF = 'castellum_core.urls'
+
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
@@ -60,6 +62,10 @@ TEMPLATES = [
WSGI_APPLICATION = 'castellum_core.wsgi.application'
+DATABASE_ROUTERS = [
+ 'subject_management.routers.SubjectManagementRouter',
+]
+
# Password validation
AUTH_PASSWORD_VALIDATORS = [
diff --git a/castellum_core/castellum_core/castellum_core/settings/development.py b/castellum_core/castellum_core/castellum_core/settings/development.py
index 3be75ce80ab6005a8a94da3a9d7ce3ee89e6700f..c4579e987fa77a7014e176c5464964bb4a2954d5 100644
--- a/castellum_core/castellum_core/castellum_core/settings/development.py
+++ b/castellum_core/castellum_core/castellum_core/settings/development.py
@@ -12,7 +12,11 @@ DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
- }
+ },
+ 'subject_management': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': os.path.join(BASE_DIR, 'subject_management.sqlite3'),
+ },
}
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
diff --git a/castellum_core/castellum_core/subject_management/__init__.py b/castellum_core/castellum_core/subject_management/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..6e59d7160d19057527329a8a868faa4188e50563
--- /dev/null
+++ b/castellum_core/castellum_core/subject_management/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'subject_management.apps.SubjectManagementConfig'
diff --git a/castellum_core/castellum_core/subject_management/admin/__init__.py b/castellum_core/castellum_core/subject_management/admin/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..067eaa8d31c5149c81744738256d17795b42dac3
--- /dev/null
+++ b/castellum_core/castellum_core/subject_management/admin/__init__.py
@@ -0,0 +1,33 @@
+# (c) 2018
+# MPIB ,
+# MPI-CBS ,
+# MPIP
+#
+# This file is part of Castellum.
+#
+# Castellum is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Castellum is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with Castellum. If not, see
+# .
+
+from django.contrib import admin
+
+from .address import AddressAdmin, CityAdmin, CountryAdmin
+from .subject import SubjectAdmin
+
+from ..models import Address, City, Country, Subject
+
+
+admin.site.register(Address, AddressAdmin)
+admin.site.register(City, CityAdmin)
+admin.site.register(Country, CountryAdmin)
+admin.site.register(Subject, SubjectAdmin)
diff --git a/castellum_core/castellum_core/subject_management/admin/address.py b/castellum_core/castellum_core/subject_management/admin/address.py
new file mode 100644
index 0000000000000000000000000000000000000000..37f6f946df1af72ba3643ef83aef56303ec45148
--- /dev/null
+++ b/castellum_core/castellum_core/subject_management/admin/address.py
@@ -0,0 +1,36 @@
+# (c) 2018
+# MPIB ,
+# MPI-CBS ,
+# MPIP
+#
+# This file is part of Castellum.
+#
+# Castellum is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Castellum is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with Castellum. If not, see
+# .
+
+from django.contrib import admin
+
+
+class CountryAdmin(admin.ModelAdmin):
+ pass
+
+
+class CityAdmin(admin.ModelAdmin):
+ list_display = "name", "country",
+ list_per_page = 200
+
+
+class AddressAdmin(admin.ModelAdmin):
+ list_display = "city", "zip_code", "street", "house_number", "additional_information"
+ list_per_page = 200
diff --git a/castellum_core/castellum_core/subject_management/admin/subject.py b/castellum_core/castellum_core/subject_management/admin/subject.py
new file mode 100644
index 0000000000000000000000000000000000000000..af60709800ad293068306a05edaece4370dd5133
--- /dev/null
+++ b/castellum_core/castellum_core/subject_management/admin/subject.py
@@ -0,0 +1,42 @@
+# (c) 2018
+# MPIB ,
+# MPI-CBS ,
+# MPIP
+#
+# This file is part of Castellum.
+#
+# Castellum is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Castellum is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with Castellum. If not, see
+# .
+
+from django.contrib import admin
+
+
+class SubjectAdmin(admin.ModelAdmin):
+ list_display = "first_name", "last_name", "address", "email", "phone_number"
+ list_display_links = "first_name", "last_name"
+ list_per_page = 200
+ search_fields = "first_name", "last_name"
+
+ fieldsets = (
+ (None, {
+ "fields": (
+ ("first_name", "last_name"),
+ "gender",
+ "birthday",
+ ),
+ }),
+ ("Contact Data", {
+ "fields": ("address", "email", ("phone_number", "phone_number_alternative"))
+ }),
+ )
diff --git a/castellum_core/castellum_core/subject_management/apps.py b/castellum_core/castellum_core/subject_management/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..778ea66e54b5074704b29c542e5ef5d3813525b4
--- /dev/null
+++ b/castellum_core/castellum_core/subject_management/apps.py
@@ -0,0 +1,26 @@
+# (c) 2018
+# MPIB ,
+# MPI-CBS ,
+# MPIP
+#
+# This file is part of Castellum.
+#
+# Castellum is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Castellum is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with Castellum. If not, see
+# .
+
+from django.apps import AppConfig
+
+
+class SubjectManagementConfig(AppConfig):
+ name = 'subject_management'
diff --git a/castellum_core/castellum_core/subject_management/migrations/0001_initial.py b/castellum_core/castellum_core/subject_management/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b0595c9b66d5d82ebaa8284e2513f08a5096027
--- /dev/null
+++ b/castellum_core/castellum_core/subject_management/migrations/0001_initial.py
@@ -0,0 +1,83 @@
+# Generated by Django 2.0.4 on 2018-05-31 11:02
+
+from django.db import migrations, models
+import django.db.models.deletion
+import uuid
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Address',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('zip_code', models.CharField(max_length=5)),
+ ('street', models.CharField(max_length=128)),
+ ('house_number', models.CharField(max_length=5)),
+ ('additional_information', models.CharField(blank=True, default='', max_length=32)),
+ ],
+ options={
+ 'verbose_name_plural': 'Addresses',
+ 'ordering': ('city__country__name', 'city__name', 'zip_code', 'street', 'house_number', 'additional_information'),
+ 'verbose_name': 'Address',
+ },
+ ),
+ migrations.CreateModel(
+ name='City',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=128)),
+ ],
+ options={
+ 'verbose_name_plural': 'Cities',
+ 'ordering': ('country__name', 'name'),
+ 'verbose_name': 'City',
+ },
+ ),
+ migrations.CreateModel(
+ name='Country',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=64, unique=True)),
+ ],
+ options={
+ 'verbose_name_plural': 'Countries',
+ 'ordering': ('name',),
+ 'verbose_name': 'Country',
+ },
+ ),
+ migrations.CreateModel(
+ name='Subject',
+ fields=[
+ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
+ ('first_name', models.CharField(max_length=64)),
+ ('last_name', models.CharField(max_length=64)),
+ ('gender', models.CharField(choices=[('f', 'female'), ('m', 'male')], default='f', max_length=1)),
+ ('birthday', models.DateField()),
+ ('email', models.EmailField(blank=True, default='', max_length=128)),
+ ('phone_number', models.CharField(blank=True, default='', max_length=32)),
+ ('phone_number_alternative', models.CharField(blank=True, default='', max_length=32)),
+ ('address', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='subject_management.Address')),
+ ],
+ ),
+ migrations.AddField(
+ model_name='city',
+ name='country',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subject_management.Country'),
+ ),
+ migrations.AddField(
+ model_name='address',
+ name='city',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subject_management.City'),
+ ),
+ migrations.AlterUniqueTogether(
+ name='city',
+ unique_together={('name', 'country')},
+ ),
+ ]
diff --git a/castellum_core/castellum_core/subject_management/migrations/0002_auto_20180607_1232.py b/castellum_core/castellum_core/subject_management/migrations/0002_auto_20180607_1232.py
new file mode 100644
index 0000000000000000000000000000000000000000..24245d02d9df68d1b02dab6872cc61105187602b
--- /dev/null
+++ b/castellum_core/castellum_core/subject_management/migrations/0002_auto_20180607_1232.py
@@ -0,0 +1,94 @@
+# Generated by Django 2.0.4 on 2018-06-07 12:32
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('subject_management', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='address',
+ name='additional_information',
+ field=models.CharField(blank=True, max_length=32, verbose_name='additional information'),
+ ),
+ migrations.AlterField(
+ model_name='address',
+ name='city',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subject_management.City', verbose_name='City'),
+ ),
+ migrations.AlterField(
+ model_name='address',
+ name='house_number',
+ field=models.CharField(max_length=5, verbose_name='house_number'),
+ ),
+ migrations.AlterField(
+ model_name='address',
+ name='street',
+ field=models.CharField(max_length=128, verbose_name='street'),
+ ),
+ migrations.AlterField(
+ model_name='address',
+ name='zip_code',
+ field=models.CharField(max_length=5, verbose_name='zip code'),
+ ),
+ migrations.AlterField(
+ model_name='city',
+ name='country',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subject_management.Country', verbose_name='Country'),
+ ),
+ migrations.AlterField(
+ model_name='city',
+ name='name',
+ field=models.CharField(max_length=128, verbose_name='name'),
+ ),
+ migrations.AlterField(
+ model_name='country',
+ name='name',
+ field=models.CharField(max_length=64, unique=True, verbose_name='name'),
+ ),
+ migrations.AlterField(
+ model_name='subject',
+ name='address',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='subject_management.Address', verbose_name='Address'),
+ ),
+ migrations.AlterField(
+ model_name='subject',
+ name='birthday',
+ field=models.DateField(verbose_name='birthday'),
+ ),
+ migrations.AlterField(
+ model_name='subject',
+ name='email',
+ field=models.EmailField(blank=True, max_length=128, verbose_name='email'),
+ ),
+ migrations.AlterField(
+ model_name='subject',
+ name='first_name',
+ field=models.CharField(max_length=64, verbose_name='first name'),
+ ),
+ migrations.AlterField(
+ model_name='subject',
+ name='gender',
+ field=models.CharField(choices=[('f', 'female'), ('m', 'male'), ('*', 'diverse')], default='f', max_length=1, verbose_name='gender'),
+ ),
+ migrations.AlterField(
+ model_name='subject',
+ name='last_name',
+ field=models.CharField(max_length=64, verbose_name='last name'),
+ ),
+ migrations.AlterField(
+ model_name='subject',
+ name='phone_number',
+ field=models.CharField(blank=True, max_length=32, verbose_name='phone number'),
+ ),
+ migrations.AlterField(
+ model_name='subject',
+ name='phone_number_alternative',
+ field=models.CharField(blank=True, max_length=32, verbose_name='phone number alternative'),
+ ),
+ ]
diff --git a/castellum_core/castellum_core/subject_management/migrations/__init__.py b/castellum_core/castellum_core/subject_management/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/castellum_core/castellum_core/subject_management/models/__init__.py b/castellum_core/castellum_core/subject_management/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..026d42f6e4458cbbd49449c0d45950e653e5db6e
--- /dev/null
+++ b/castellum_core/castellum_core/subject_management/models/__init__.py
@@ -0,0 +1,26 @@
+# (c) 2018
+# MPIB ,
+# MPI-CBS ,
+# MPIP
+#
+# This file is part of Castellum.
+#
+# Castellum is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Castellum is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with Castellum. If not, see
+# .
+
+from .address import Address, City, Country
+from .subject import Subject
+
+
+__all__ = Address, City, Country, Subject
diff --git a/castellum_core/castellum_core/subject_management/models/address.py b/castellum_core/castellum_core/subject_management/models/address.py
new file mode 100644
index 0000000000000000000000000000000000000000..1e1a7faee0e37eb8a88fa15cd2338d36b53a9664
--- /dev/null
+++ b/castellum_core/castellum_core/subject_management/models/address.py
@@ -0,0 +1,68 @@
+# (c) 2018
+# MPIB ,
+# MPI-CBS ,
+# MPIP
+#
+# This file is part of Castellum.
+#
+# Castellum is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Castellum is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with Castellum. If not, see
+# .
+
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+
+class Country(models.Model):
+ name = models.CharField(_("name"), max_length=64, unique=True)
+
+ def __str__(self):
+ return self.name
+
+ class Meta:
+ ordering = "name",
+ verbose_name = _("Country")
+ verbose_name_plural = _("Countries")
+
+
+class City(models.Model):
+ name = models.CharField(_("name"), max_length=128)
+ country = models.ForeignKey(Country, verbose_name=_("Country"), on_delete=models.CASCADE)
+
+ def __str__(self):
+ return "{}, {}".format(self.name, self.country.name)
+
+ class Meta:
+ ordering = "country__name", "name"
+ unique_together = "name", "country"
+ verbose_name = _("City")
+ verbose_name_plural = _("Cities")
+
+
+class Address(models.Model):
+ city = models.ForeignKey(City, verbose_name=_("City"), on_delete=models.CASCADE)
+ zip_code = models.CharField(_("zip code"), max_length=5)
+ street = models.CharField(_("street"), max_length=128)
+ house_number = models.CharField(_("house_number"), max_length=5)
+ additional_information = models.CharField(_("additional information"), max_length=32,
+ blank=True)
+
+ def __str__(self):
+ street = " ".join([self.street, self.house_number, self.additional_information]).strip()
+ return "{} {}, {}".format(self.zip_code, self.city.name, street)
+
+ class Meta:
+ ordering = ("city__country__name", "city__name", "zip_code", "street", "house_number",
+ "additional_information")
+ verbose_name = _("Address")
+ verbose_name_plural = _("Addresses")
diff --git a/castellum_core/castellum_core/subject_management/models/subject.py b/castellum_core/castellum_core/subject_management/models/subject.py
new file mode 100644
index 0000000000000000000000000000000000000000..335e9f7f361449d5b939d8e83f99319dc3f2eaed
--- /dev/null
+++ b/castellum_core/castellum_core/subject_management/models/subject.py
@@ -0,0 +1,51 @@
+# (c) 2018
+# MPIB ,
+# MPI-CBS ,
+# MPIP
+#
+# This file is part of Castellum.
+#
+# Castellum is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Castellum is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with Castellum. If not, see
+# .
+
+import uuid
+
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+from . import Address
+
+
+class Subject(models.Model):
+ GENDER = (
+ ("f", _("female")),
+ ("m", _("male")),
+ ("*", _("diverse")),
+ )
+
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
+
+ first_name = models.CharField(_("first name"), max_length=64)
+ last_name = models.CharField(_("last name"), max_length=64)
+
+ gender = models.CharField(_("gender"), max_length=1, choices=GENDER, default="f")
+
+ birthday = models.DateField(_("birthday"))
+
+ address = models.ForeignKey(Address, blank=True, null=True, verbose_name=_("Address"),
+ on_delete=models.SET_NULL)
+ email = models.EmailField(_("email"), max_length=128, blank=True)
+ phone_number = models.CharField(_("phone number"), max_length=32, blank=True)
+ phone_number_alternative = models.CharField(_("phone number alternative"), max_length=32,
+ blank=True)
diff --git a/castellum_core/castellum_core/subject_management/routers.py b/castellum_core/castellum_core/subject_management/routers.py
new file mode 100644
index 0000000000000000000000000000000000000000..d30f649470a832f715becd6bd64eca4b37d7b72f
--- /dev/null
+++ b/castellum_core/castellum_core/subject_management/routers.py
@@ -0,0 +1,42 @@
+# (c) 2018
+# MPIB ,
+# MPI-CBS ,
+# MPIP
+#
+# This file is part of Castellum.
+#
+# Castellum is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Castellum is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with Castellum. If not, see
+# .
+
+APP_LABEL = "subject_management"
+
+
+class SubjectManagementRouter:
+ def db_for_read(self, model, **hints):
+ if model._meta.app_label == APP_LABEL:
+ return APP_LABEL
+
+ def db_for_write(self, model, **hints):
+ if model._meta.app_label == APP_LABEL:
+ return APP_LABEL
+
+ def allow_relation(self, obj1, obj2, **hints):
+ if obj1._meta.app_label == obj2._meta.app_label and obj1._meta.app_label == APP_LABEL:
+ return True
+
+ def allow_migrate(self, db, app_label, **hints):
+ if db == APP_LABEL:
+ return app_label == APP_LABEL
+ elif app_label == APP_LABEL:
+ return False
diff --git a/castellum_core/tests/subject_management/models/conftest.py b/castellum_core/tests/subject_management/models/conftest.py
new file mode 100644
index 0000000000000000000000000000000000000000..a1d5cb7d169cdc60349bbadbd2a298c5bed654fd
--- /dev/null
+++ b/castellum_core/tests/subject_management/models/conftest.py
@@ -0,0 +1,19 @@
+import pytest
+
+from subject_management.models import Address, City, Country
+
+
+@pytest.fixture
+def country():
+ return Country(name="Germany")
+
+
+@pytest.fixture
+def city(country):
+ return City(name="Berlin", country=country)
+
+
+@pytest.fixture
+def address(city):
+ return Address(city=city, zip_code="10787", street="Hardenbergplatz", house_number="8",
+ additional_information="")
diff --git a/castellum_core/tests/subject_management/models/test_address.py b/castellum_core/tests/subject_management/models/test_address.py
new file mode 100644
index 0000000000000000000000000000000000000000..4343074235506cc03a8260420ff5fcc577e5477a
--- /dev/null
+++ b/castellum_core/tests/subject_management/models/test_address.py
@@ -0,0 +1,7 @@
+def test_str(address):
+ assert "10787 Berlin, Hardenbergplatz 8" == str(address)
+
+
+def test_str_with_additional_information(address):
+ address.additional_information = "appartment 3"
+ assert "10787 Berlin, Hardenbergplatz 8 appartment 3" == str(address)
diff --git a/castellum_core/tests/subject_management/models/test_city.py b/castellum_core/tests/subject_management/models/test_city.py
new file mode 100644
index 0000000000000000000000000000000000000000..7d137b2f145d32653bd9753de258a644d6c1ed88
--- /dev/null
+++ b/castellum_core/tests/subject_management/models/test_city.py
@@ -0,0 +1,2 @@
+def test_str(city):
+ assert "Berlin, Germany" == str(city)
diff --git a/castellum_core/tests/subject_management/models/test_country.py b/castellum_core/tests/subject_management/models/test_country.py
new file mode 100644
index 0000000000000000000000000000000000000000..81ecc6724c0a01bce9bedcbc0a40e0580b02706a
--- /dev/null
+++ b/castellum_core/tests/subject_management/models/test_country.py
@@ -0,0 +1,2 @@
+def test_str(country):
+ assert "Germany" == str(country)
diff --git a/castellum_core/tests/subject_management/test_router.py b/castellum_core/tests/subject_management/test_router.py
new file mode 100644
index 0000000000000000000000000000000000000000..909103125d93778e5cc36cf5d697126e1d5ee122
--- /dev/null
+++ b/castellum_core/tests/subject_management/test_router.py
@@ -0,0 +1,48 @@
+import pytest
+
+from model_mommy import mommy
+
+from castellum_auth.models import User
+from subject_management.models import Subject
+from subject_management.routers import APP_LABEL, SubjectManagementRouter
+
+
+@pytest.fixture
+def router():
+ return SubjectManagementRouter()
+
+
+@pytest.mark.parametrize("model,expected", [
+ (Subject, "subject_management"),
+ (User, None),
+])
+def test_db_for_read(router, model, expected):
+ assert expected == router.db_for_read(model)
+
+
+@pytest.mark.parametrize("model,expected", [
+ (Subject, "subject_management"),
+ (User, None),
+])
+def test_db_for_write(router, model, expected):
+ assert expected == router.db_for_write(model)
+
+
+@pytest.mark.parametrize("obj1,obj2,expected", [
+ (mommy.prepare(Subject), mommy.prepare(Subject), True),
+ (mommy.prepare(Subject), mommy.prepare(User), None),
+ (mommy.prepare(User), mommy.prepare(Subject), None),
+ (mommy.prepare(User), mommy.prepare(User), None),
+])
+def test_allow_relation(router, obj1, obj2, expected):
+ assert expected == router.allow_relation(obj1, obj2)
+
+
+@pytest.mark.parametrize("db,app_label,expected", [
+ (APP_LABEL, APP_LABEL, True),
+ ("default", APP_LABEL, False),
+ (APP_LABEL, "admin", False),
+ ("default", "admin", None),
+])
+def test_allow_migrate(router, db, app_label, expected):
+ assert expected == router.allow_migrate(db, app_label)
diff --git a/example_deployment/settings.py b/example_deployment/settings.py
index cfdfa29422931eba8cffd1fb80bd567abf461a23..2ddc3429be387be1cf666269e8b76ecfeb9bd619 100644
--- a/example_deployment/settings.py
+++ b/example_deployment/settings.py
@@ -15,6 +15,12 @@ DATABASES = {
'NAME': 'postgres',
'USER': 'postgres',
'HOST': 'db',
+ },
+ 'subject_management': {
+ 'ENGINE': 'django.db.backends.postgresql',
+ 'NAME': 'postgres',
+ 'USER': 'postgres',
+ 'HOST': 'db',
}
}