From b78ac2eb705d2b27b6c9f9625405068e8ba6ae29 Mon Sep 17 00:00:00 2001 From: claasga Date: Tue, 6 Aug 2024 16:23:08 +0200 Subject: [PATCH 1/2] backend: make mixins more consistent --- .../game/migrations/0001_initial.py | 779 +++++++++++++++--- .../dps_training_k/game/models/exercise.py | 3 +- backend/dps_training_k/game/models/lab.py | 4 +- .../game/models/patient_instance.py | 7 +- .../helpers/completed_actions.py | 11 +- backend/dps_training_k/helpers/eventable.py | 31 - 6 files changed, 658 insertions(+), 177 deletions(-) delete mode 100644 backend/dps_training_k/helpers/eventable.py diff --git a/backend/dps_training_k/game/migrations/0001_initial.py b/backend/dps_training_k/game/migrations/0001_initial.py index 05a62803..8e9d8563 100644 --- a/backend/dps_training_k/game/migrations/0001_initial.py +++ b/backend/dps_training_k/game/migrations/0001_initial.py @@ -5,7 +5,6 @@ import django.db.models.deletion import django.utils.timezone import game.models.patient_instance -import helpers.eventable import helpers.local_timable from django.conf import settings from django.db import migrations, models @@ -16,226 +15,740 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('auth', '0012_alter_user_first_name_max_length'), - ('template', '0001_initial'), + ("auth", "0012_alter_user_first_name_max_length"), + ("template", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Area', + name="Area", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('isPaused', models.BooleanField(default=False)), - ('name', models.CharField(max_length=30)), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("isPaused", models.BooleanField(default=False)), + ("name", models.CharField(max_length=30)), ], ), migrations.CreateModel( - name='Exercise', + name="Exercise", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('frontend_id', models.CharField(unique=True)), - ('state', models.CharField(choices=[('C', 'configuration'), ('R', 'running'), ('P', 'paused'), ('F', 'finished')], default='C')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("frontend_id", models.CharField(unique=True)), + ( + "state", + models.CharField( + choices=[ + ("C", "configuration"), + ("R", "running"), + ("P", "paused"), + ("F", "finished"), + ], + default="C", + ), + ), ], - bases=(helpers.eventable.NonEventable, models.Model), ), migrations.CreateModel( - name='SavedExercise', + name="SavedExercise", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(unique=True)), - ('saved_exercise', models.JSONField()), - ('time_speed_up', models.FloatField(default=1.0)), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(unique=True)), + ("saved_exercise", models.JSONField()), + ("time_speed_up", models.FloatField(default=1.0)), ], ), migrations.CreateModel( - name='User', + name="User", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('password', models.CharField(max_length=128, verbose_name='password')), - ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), - ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), - ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), - ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), - ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), - ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), - ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), - ('user_type', models.CharField(choices=[('P', 'Patient'), ('T', 'Trainer')], default='P', max_length=1)), - ('channel_name', models.CharField(blank=True, max_length=100, null=True)), - ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("password", models.CharField(max_length=128, verbose_name="password")), + ( + "last_login", + models.DateTimeField( + blank=True, null=True, verbose_name="last login" + ), + ), + ( + "is_superuser", + models.BooleanField( + default=False, + help_text="Designates that this user has all permissions without explicitly assigning them.", + verbose_name="superuser status", + ), + ), + ( + "username", + models.CharField( + error_messages={ + "unique": "A user with that username already exists." + }, + help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", + max_length=150, + unique=True, + validators=[ + django.contrib.auth.validators.UnicodeUsernameValidator() + ], + verbose_name="username", + ), + ), + ( + "first_name", + models.CharField( + blank=True, max_length=150, verbose_name="first name" + ), + ), + ( + "last_name", + models.CharField( + blank=True, max_length=150, verbose_name="last name" + ), + ), + ( + "email", + models.EmailField( + blank=True, max_length=254, verbose_name="email address" + ), + ), + ( + "is_staff", + models.BooleanField( + default=False, + help_text="Designates whether the user can log into this admin site.", + verbose_name="staff status", + ), + ), + ( + "is_active", + models.BooleanField( + default=True, + help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", + verbose_name="active", + ), + ), + ( + "date_joined", + models.DateTimeField( + default=django.utils.timezone.now, verbose_name="date joined" + ), + ), + ( + "user_type", + models.CharField( + choices=[("P", "Patient"), ("T", "Trainer")], + default="P", + max_length=1, + ), + ), + ( + "channel_name", + models.CharField(blank=True, max_length=100, null=True), + ), + ( + "groups", + models.ManyToManyField( + blank=True, + help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", + related_name="user_set", + related_query_name="user", + to="auth.group", + verbose_name="groups", + ), + ), + ( + "user_permissions", + models.ManyToManyField( + blank=True, + help_text="Specific permissions for this user.", + related_name="user_set", + related_query_name="user", + to="auth.permission", + verbose_name="user permissions", + ), + ), ], options={ - 'verbose_name': 'User', - 'verbose_name_plural': 'Users', + "verbose_name": "User", + "verbose_name_plural": "Users", }, managers=[ - ('objects', django.contrib.auth.models.UserManager()), + ("objects", django.contrib.auth.models.UserManager()), ], ), migrations.CreateModel( - name='ActionInstance', + name="ActionInstance", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('order_id', models.IntegerField(null=True)), - ('historic_patient_state', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='template.patientstate')), - ('template', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='template.action')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("order_id", models.IntegerField(null=True)), + ( + "historic_patient_state", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="template.patientstate", + ), + ), + ( + "template", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="template.action", + ), + ), ], options={ - 'ordering': ['order_id'], + "ordering": ["order_id"], }, bases=(helpers.local_timable.LocalTimeable, models.Model), ), migrations.CreateModel( - name='ActionInstanceState', + name="ActionInstanceState", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(choices=[('PL', 'planned'), ('IP', 'in_progress'), ('OH', 'on_hold'), ('FI', 'finished'), ('IE', 'in effect'), ('EX', 'expired'), ('CA', 'canceled')], max_length=2)), - ('t_local_begin', models.IntegerField()), - ('t_local_end', models.IntegerField(blank=True, null=True)), - ('info_text', models.CharField(blank=True, default=None, null=True)), - ('action_instance', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='states', to='game.actioninstance')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField( + choices=[ + ("PL", "planned"), + ("IP", "in_progress"), + ("OH", "on_hold"), + ("FI", "finished"), + ("IE", "in effect"), + ("EX", "expired"), + ("CA", "canceled"), + ], + max_length=2, + ), + ), + ("t_local_begin", models.IntegerField()), + ("t_local_end", models.IntegerField(blank=True, null=True)), + ("info_text", models.CharField(blank=True, default=None, null=True)), + ( + "action_instance", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="states", + to="game.actioninstance", + ), + ), ], ), migrations.AddField( - model_name='actioninstance', - name='current_state', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='game.actioninstancestate'), + model_name="actioninstance", + name="current_state", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="game.actioninstancestate", + ), ), migrations.AddField( - model_name='actioninstance', - name='area', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='game.area'), + model_name="actioninstance", + name="area", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="+", + to="game.area", + ), ), migrations.AddField( - model_name='area', - name='exercise', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='game.exercise'), + model_name="area", + name="exercise", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="game.exercise" + ), ), migrations.CreateModel( - name='Lab', + name="Lab", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('exercise', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='game.exercise')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "exercise", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, to="game.exercise" + ), + ), ], ), migrations.AddField( - model_name='actioninstance', - name='lab', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='game.lab'), + model_name="actioninstance", + name="lab", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="game.lab", + ), ), migrations.CreateModel( - name='PatientInstance', + name="PatientInstance", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(default='Max Mustermann', max_length=100)), - ('frontend_id', models.CharField(help_text='patient_frontend_id used to log into patient - see validator for format', max_length=6, unique=True, validators=[game.models.patient_instance.validate_patient_frontend_id])), - ('triage', models.CharField(choices=[('-', 'Gray'), ('X', 'Black'), ('1', 'Red'), ('2', 'Yellow'), ('3', 'Green')], default='-')), - ('area', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='game.area')), - ('exercise', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='game.exercise')), - ('patient_state', models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='template.patientstate')), - ('static_information', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='template.patientinformation')), - ('user', models.OneToOneField(blank=True, help_text='User object for authentication - has to be deleted explicitly or manually', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(default="Max Mustermann", max_length=100)), + ( + "frontend_id", + models.CharField( + help_text="patient_frontend_id used to log into patient - see validator for format", + max_length=6, + unique=True, + validators=[ + game.models.patient_instance.validate_patient_frontend_id + ], + ), + ), + ( + "triage", + models.CharField( + choices=[ + ("-", "Gray"), + ("X", "Black"), + ("1", "Red"), + ("2", "Yellow"), + ("3", "Green"), + ], + default="-", + ), + ), + ( + "area", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="game.area" + ), + ), + ( + "exercise", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="game.exercise" + ), + ), + ( + "patient_state", + models.ForeignKey( + default=None, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="template.patientstate", + ), + ), + ( + "static_information", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="template.patientinformation", + ), + ), + ( + "user", + models.OneToOneField( + blank=True, + help_text="User object for authentication - has to be deleted explicitly or manually", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + ), + ), ], - bases=(helpers.eventable.Eventable, models.Model), ), migrations.CreateModel( - name='MaterialInstance', + name="MaterialInstance", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('action_instance', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='game.actioninstance')), - ('area', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='game.area')), - ('lab', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='game.lab')), - ('template', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='template.material')), - ('patient_instance', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='game.patientinstance')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "action_instance", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="game.actioninstance", + ), + ), + ( + "area", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="game.area", + ), + ), + ( + "lab", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="game.lab", + ), + ), + ( + "template", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="template.material", + ), + ), + ( + "patient_instance", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="game.patientinstance", + ), + ), ], ), migrations.AddField( - model_name='actioninstance', - name='patient_instance', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='game.patientinstance'), + model_name="actioninstance", + name="patient_instance", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="game.patientinstance", + ), ), migrations.CreateModel( - name='Personnel', + name="Personnel", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(blank=True, max_length=100)), - ('action_instance', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='game.actioninstance')), - ('area', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='game.area')), - ('lab', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='game.lab')), - ('patient_instance', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='game.patientinstance')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(blank=True, max_length=100)), + ( + "action_instance", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="game.actioninstance", + ), + ), + ( + "area", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="game.area", + ), + ), + ( + "lab", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="game.lab", + ), + ), + ( + "patient_instance", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="game.patientinstance", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='LogEntry', + name="LogEntry", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('local_id', models.IntegerField(blank=True)), - ('timestamp', models.DateTimeField(blank=True, help_text='May only be set while exercise is running', null=True)), - ('message', models.TextField()), - ('is_dirty', models.BooleanField(default=False, help_text='Set to True if objects is missing relevant Keys (e.g. timestamp)')), - ('area', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='game.area')), - ('exercise', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='game.exercise')), - ('materials', models.ManyToManyField(blank=True, to='game.materialinstance')), - ('patient_instance', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='game.patientinstance')), - ('personnel', models.ManyToManyField(blank=True, to='game.personnel')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("local_id", models.IntegerField(blank=True)), + ( + "timestamp", + models.DateTimeField( + blank=True, + help_text="May only be set while exercise is running", + null=True, + ), + ), + ("message", models.TextField()), + ( + "is_dirty", + models.BooleanField( + default=False, + help_text="Set to True if objects is missing relevant Keys (e.g. timestamp)", + ), + ), + ( + "area", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="game.area", + ), + ), + ( + "exercise", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="game.exercise" + ), + ), + ( + "materials", + models.ManyToManyField(blank=True, to="game.materialinstance"), + ), + ( + "patient_instance", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="game.patientinstance", + ), + ), + ("personnel", models.ManyToManyField(blank=True, to="game.personnel")), ], ), migrations.AddField( - model_name='exercise', - name='config', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='game.savedexercise'), + model_name="exercise", + name="config", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="game.savedexercise", + ), ), migrations.CreateModel( - name='ScheduledEvent', + name="ScheduledEvent", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('end_date', models.DateTimeField()), - ('kwargs', models.TextField(blank=True, null=True)), - ('method_name', models.CharField(max_length=100)), - ('exercise', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events', to='game.exercise')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("end_date", models.DateTimeField()), + ("kwargs", models.TextField(blank=True, null=True)), + ("method_name", models.CharField(max_length=100)), + ( + "exercise", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="events", + to="game.exercise", + ), + ), ], options={ - 'ordering': ['exercise', 'end_date'], + "ordering": ["exercise", "end_date"], }, ), migrations.CreateModel( - name='Owner', + name="Owner", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('action_instance_owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='owned_events', to='game.actioninstance')), - ('area_owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='owned_events', to='game.area')), - ('exercise_owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='owned_events', to='game.exercise')), - ('patient_owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='owned_events', to='game.patientinstance')), - ('event', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='game.scheduledevent')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "action_instance_owner", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="owned_events", + to="game.actioninstance", + ), + ), + ( + "area_owner", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="owned_events", + to="game.area", + ), + ), + ( + "exercise_owner", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="owned_events", + to="game.exercise", + ), + ), + ( + "patient_owner", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="owned_events", + to="game.patientinstance", + ), + ), + ( + "event", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + to="game.scheduledevent", + ), + ), ], ), migrations.AddConstraint( - model_name='area', - constraint=models.UniqueConstraint(fields=('name', 'exercise'), name='unique_area_names_per_exercise'), + model_name="area", + constraint=models.UniqueConstraint( + fields=("name", "exercise"), name="unique_area_names_per_exercise" + ), ), migrations.AddConstraint( - model_name='materialinstance', - constraint=models.CheckConstraint(check=models.Q(('lab__isnull', False), ('patient_instance__isnull', False), ('area__isnull', False), _connector='OR'), name='one_or_more_field_not_null_material'), + model_name="materialinstance", + constraint=models.CheckConstraint( + check=models.Q( + ("lab__isnull", False), + ("patient_instance__isnull", False), + ("area__isnull", False), + _connector="OR", + ), + name="one_or_more_field_not_null_material", + ), ), migrations.AddConstraint( - model_name='actioninstance', - constraint=models.UniqueConstraint(fields=('order_id', 'patient_instance'), name='unique_order_id_for_patient'), + model_name="actioninstance", + constraint=models.UniqueConstraint( + fields=("order_id", "patient_instance"), + name="unique_order_id_for_patient", + ), ), migrations.AddConstraint( - model_name='actioninstance', - constraint=models.CheckConstraint(check=models.Q(('lab__isnull', False), ('patient_instance__isnull', False), _connector='OR'), name='one_or_more_field_not_null_action'), + model_name="actioninstance", + constraint=models.CheckConstraint( + check=models.Q( + ("lab__isnull", False), + ("patient_instance__isnull", False), + _connector="OR", + ), + name="one_or_more_field_not_null_action", + ), ), migrations.AddConstraint( - model_name='logentry', - constraint=models.UniqueConstraint(fields=('local_id', 'exercise'), name='unique_local_id_for_entry'), + model_name="logentry", + constraint=models.UniqueConstraint( + fields=("local_id", "exercise"), name="unique_local_id_for_entry" + ), ), migrations.AddConstraint( - model_name='owner', - constraint=models.CheckConstraint(check=models.Q(('action_instance_owner__isnull', False), ('patient_owner__isnull', False), ('exercise_owner__isnull', False), ('area_owner__isnull', False), _connector='OR'), name='one_or_more_field_not_null_owner'), + model_name="owner", + constraint=models.CheckConstraint( + check=models.Q( + ("action_instance_owner__isnull", False), + ("patient_owner__isnull", False), + ("exercise_owner__isnull", False), + ("area_owner__isnull", False), + _connector="OR", + ), + name="one_or_more_field_not_null_owner", + ), ), ] diff --git a/backend/dps_training_k/game/models/exercise.py b/backend/dps_training_k/game/models/exercise.py index a59739cc..e7262774 100644 --- a/backend/dps_training_k/game/models/exercise.py +++ b/backend/dps_training_k/game/models/exercise.py @@ -2,13 +2,12 @@ from django.db import models from game.channel_notifications import ExerciseDispatcher -from helpers.eventable import NonEventable from .lab import Lab from .scheduled_event import ScheduledEvent from .log_entry import LogEntry -class Exercise(NonEventable, models.Model): +class Exercise(models.Model): class StateTypes(models.TextChoices): CONFIGURATION = "C", "configuration" RUNNING = "R", "running" diff --git a/backend/dps_training_k/game/models/lab.py b/backend/dps_training_k/game/models/lab.py index c7d02a60..cd8d6642 100644 --- a/backend/dps_training_k/game/models/lab.py +++ b/backend/dps_training_k/game/models/lab.py @@ -2,14 +2,14 @@ from game.models import MaterialInstance from helpers.moveable_to import MoveableTo -from helpers.completed_actions import CompletedActionsMixin +from helpers.completed_actions import CompletedActionsGetable from game.models import MaterialInstance from template.models import Material from template.constants import MaterialIDs from template.models import Material -class Lab(MoveableTo, CompletedActionsMixin): +class Lab(MoveableTo, CompletedActionsGetable, models.Model): exercise = models.OneToOneField( "Exercise", on_delete=models.CASCADE, diff --git a/backend/dps_training_k/game/models/patient_instance.py b/backend/dps_training_k/game/models/patient_instance.py index 4d82aebf..91d559b7 100644 --- a/backend/dps_training_k/game/models/patient_instance.py +++ b/backend/dps_training_k/game/models/patient_instance.py @@ -7,11 +7,10 @@ from configuration import settings from game.models import Exercise from game.channel_notifications import PatientInstanceDispatcher -from helpers.eventable import Eventable from helpers.moveable import Moveable from helpers.moveable_to import MoveableTo from helpers.triage import Triage -from helpers.completed_actions import CompletedActionsMixin +from helpers.completed_actions import CompletedActionsGetable from template.models import PatientState, Action, Subcondition, Material # from game.models import ActionInstanceStateNames moved into function to avoid circular imports @@ -28,9 +27,7 @@ def validate_patient_frontend_id(value): ) -class PatientInstance( - CompletedActionsMixin, Eventable, Moveable, MoveableTo, models.Model -): +class PatientInstance(CompletedActionsGetable, Moveable, MoveableTo, models.Model): area = models.ForeignKey("Area", on_delete=models.CASCADE, null=True, blank=True) lab = models.ForeignKey("Lab", on_delete=models.CASCADE, null=True, blank=True) exercise = models.ForeignKey("Exercise", on_delete=models.CASCADE) diff --git a/backend/dps_training_k/helpers/completed_actions.py b/backend/dps_training_k/helpers/completed_actions.py index 07958e8c..601ffd6a 100644 --- a/backend/dps_training_k/helpers/completed_actions.py +++ b/backend/dps_training_k/helpers/completed_actions.py @@ -1,10 +1,13 @@ - -class CompletedActionsMixin: +class CompletedActionsGetable: def get_completed_action_types(self): from game.models import ActionInstanceState + action_instances = self.actioninstance_set.select_related("template").all() applied_actions = set() for action_instance in action_instances: - if action_instance.current_state.name in ActionInstanceState.completion_states(): + if ( + action_instance.current_state.name + in ActionInstanceState.completion_states() + ): applied_actions.add(action_instance.template) - return applied_actions \ No newline at end of file + return applied_actions diff --git a/backend/dps_training_k/helpers/eventable.py b/backend/dps_training_k/helpers/eventable.py deleted file mode 100644 index eb9c4205..00000000 --- a/backend/dps_training_k/helpers/eventable.py +++ /dev/null @@ -1,31 +0,0 @@ -from abc import abstractmethod - - -class AbstractEventable: - - @abstractmethod - def schedule_events(self): - pass - - @abstractmethod - def remove_events(self): - pass - - -class NonEventable(AbstractEventable): - - def schedule_events(self): - pass - - def remove_events(self): - pass - - -class Eventable(AbstractEventable): - """ - This mixin provides the functionality of removing and scheduling all current events - """ - - def remove_events(self): - for event in self.owned_events.all(): - event.delete() From 7fe2ba5322116a00eee6e5c175ac918f2fbfc76f Mon Sep 17 00:00:00 2001 From: claasga Date: Tue, 6 Aug 2024 16:38:04 +0200 Subject: [PATCH 2/2] backend: remove meta programming from Moveable mixin for better composition --- backend/dps_training_k/helpers/moveable.py | 4 +--- backend/dps_training_k/helpers/moveable_to.py | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/backend/dps_training_k/helpers/moveable.py b/backend/dps_training_k/helpers/moveable.py index 0b4bce00..c3b96d09 100644 --- a/backend/dps_training_k/helpers/moveable.py +++ b/backend/dps_training_k/helpers/moveable.py @@ -30,9 +30,7 @@ def try_moving_to(self, obj) -> tuple[bool, str]: def check_moving_to(self, obj) -> tuple[bool, str]: """Returns whether the object might be moved successfully and an error message if not.""" - from helpers.moveable_to import MoveableTo - - if not isinstance(obj, MoveableTo): + if not getattr(obj, "can_be_moved_to", False)(): raise TypeError( f"Object must inherit from MoveableTo, got {type(obj).__name__} instead." ) diff --git a/backend/dps_training_k/helpers/moveable_to.py b/backend/dps_training_k/helpers/moveable_to.py index 7260a884..bfb45236 100644 --- a/backend/dps_training_k/helpers/moveable_to.py +++ b/backend/dps_training_k/helpers/moveable_to.py @@ -39,6 +39,10 @@ def personnel_assigned(self) -> List["p.Personnel"]: def personnel_available(self) -> List["p.Personnel"]: return list(self.personnel_set.filter(action_instance=None)) + @staticmethod + def can_be_moved_to(): + return True + @staticmethod @abstractmethod def frontend_model_name():