Skip to content

Commit

Permalink
Merge pull request #153 from hpi-sam/129-n00-create-basic-exercise
Browse files Browse the repository at this point in the history
129 n00 create basic exercise
  • Loading branch information
Wolkenfarmer authored Apr 29, 2024
2 parents a369c3a + 489b438 commit 3f88906
Show file tree
Hide file tree
Showing 63 changed files with 1,533 additions and 810 deletions.
5 changes: 3 additions & 2 deletions backend/dps_training_k/configuration/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from helpers.invitation_logic import LevenshteinCode
from django.utils import timezone

from helpers.id_generator import LevenshteinCode

CODE_LENGTH = 6
INVITATION_LOGIC = LevenshteinCode(CODE_LENGTH)
ID_GENERATOR = LevenshteinCode(CODE_LENGTH)
CURRENT_TIME = lambda: timezone.now()
DEFAULT_STATE_ID = 101
42 changes: 42 additions & 0 deletions backend/dps_training_k/data/patient_information.csv

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions backend/dps_training_k/deployment/django/entrypoint
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ if [ "${RUN_MIGRATIONS:-0}" = "1" ]; then
python manage.py migrate
python manage.py collectstatic --noinput
python manage.py minimal_actions
python manage.py patient_information ./data/patient_information.csv
fi

exec "$@"
91 changes: 67 additions & 24 deletions backend/dps_training_k/game/channel_notifications.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import logging

from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer

import game.models as models # needed to avoid circular imports
import logging

"""
This package is responsible to decide when to notify which consumers.
Expand All @@ -16,7 +18,7 @@ class ChannelEventTypes:
EXERCISE_UPDATE = "send.exercise.event"
ACTION_CONFIRMATION_EVENT = "action.confirmation.event"
ACTION_DECLINATION_EVENT = "action.declination.event"
ACTION_RESULT_EVENT = "action.result.event"
ACTION_LIST_EVENT = "action.list.event"


class ChannelNotifier:
Expand All @@ -32,6 +34,12 @@ def save_and_notify(cls, obj, changes, *args, **kwargs):
super(obj.__class__, obj).save(*args, **kwargs)
cls.dispatch_event(obj, changes)

@classmethod
def delete_and_notify(cls, obj, changes):
raise NotImplementedError(
"Method delete_and_notify must be implemented by subclass"
)

@classmethod
def _notify_group(cls, group_channel_name, event):
"""
Expand All @@ -51,16 +59,26 @@ def dispatch_event(cls, obj, changes):
"Method dispatch_event must be implemented by subclass"
)

@classmethod
def _notify_exercise_update(cls, exercise):
channel = cls.get_group_name(exercise)
event = {
"type": ChannelEventTypes.EXERCISE_UPDATE,
"exercise_pk": exercise.id,
}
cls._notify_group(channel, event)


class PatientInstanceDispatcher(ChannelNotifier):

@classmethod
def dispatch_event(cls, patient_instance, changes):
if not changes:
return
if "patient_state" in changes:
if changes is not None and "patient_state" in changes:
cls._notify_patient_state_change(patient_instance)

if not (changes is not None and len(changes) == 1 and "patient_state"):
cls._notify_exercise_update(patient_instance.exercise)

@classmethod
def _notify_patient_state_change(cls, patient_instance):
channel = cls.get_group_name(patient_instance)
Expand All @@ -70,41 +88,66 @@ def _notify_patient_state_change(cls, patient_instance):
}
cls._notify_group(channel, event)

@classmethod
def delete_and_notify(cls, patient, *args, **kwargs):
exercise = patient.exercise
super(patient.__class__, patient).delete(*args, **kwargs)
cls._notify_exercise_update(exercise)


class AreaDispatcher(ChannelNotifier):
@classmethod
def dispatch_event(cls, area, changes):
cls._notify_exercise_update(area.exercise)

@classmethod
def _notify_exercise_update(cls, exercise):
channel = cls.get_group_name(exercise)
event = {
"type": ChannelEventTypes.EXERCISE_UPDATE,
"exercise_pk": exercise.id,
}
cls._notify_group(channel, event)
def delete_and_notify(cls, area, *args, **kwargs):
exercise = area.exercise
super(area.__class__, area).delete(*args, **kwargs)
cls._notify_exercise_update(exercise)


class PersonnelDispatcher(ChannelNotifier):
@classmethod
def dispatch_event(cls, personnel, changes):
cls._notify_exercise_update(personnel.area.exercise)

@classmethod
def delete_and_notify(cls, personnel, *args, **kwargs):
exercise = personnel.area.exercise
super(personnel.__class__, personnel).delete(*args, **kwargs)
cls._notify_exercise_update(exercise)


class ActionInstanceDispatcher(ChannelNotifier):
@classmethod
def dispatch_event(cls, obj, changes):
applied_action = obj
if changes and not "current_state" in changes:
if changes and not ("current_state" in changes or "order_id" in changes):
raise ValueError(
"There has to be a state change whenever updating an ActionInstance."
"There has to be a state change or order id change whenever updating an ActionInstance."
)
event_type = {
models.ActionInstanceStateNames.DECLINED: ChannelEventTypes.ACTION_DECLINATION_EVENT,
models.ActionInstanceStateNames.PLANNED: ChannelEventTypes.ACTION_CONFIRMATION_EVENT,
models.ActionInstanceStateNames.FINISHED: ChannelEventTypes.ACTION_RESULT_EVENT,
}.get(applied_action.state_name)
if event_type is None:
logging.warning(
f"No front end update for state {applied_action.state_name} send"
# state change events
if changes:
if "current_state" in changes:
if (
applied_action.state_name
== models.ActionInstanceStateNames.DECLINED
):
cls._notify_action_event(
applied_action, ChannelEventTypes.ACTION_DECLINATION_EVENT
)
elif (
applied_action.state_name == models.ActionInstanceStateNames.PLANNED
):
cls._notify_action_event(
applied_action, ChannelEventTypes.ACTION_CONFIRMATION_EVENT
)

# always send action list event
cls._notify_action_event(
applied_action, ChannelEventTypes.ACTION_LIST_EVENT
)
return
cls._notify_action_event(applied_action, event_type)

@classmethod
def _notify_action_event(cls, applied_action, event_type):
Expand Down
74 changes: 38 additions & 36 deletions backend/dps_training_k/game/consumers/abstract_consumer.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import traceback
import json
from abc import ABC, abstractmethod

from asgiref.sync import async_to_sync
from channels.generic.websocket import JsonWebsocketConsumer
from rest_framework.authtoken.models import Token

from game.models import PatientInstance, Exercise
from template.models import Action
from game.models import Exercise
from game.serializers.exercise_serializer import ExerciseSerializer
from template.models import Action, PatientInformation


class AbstractConsumer(JsonWebsocketConsumer, ABC):
Expand All @@ -24,14 +24,15 @@ class OutgoingMessageTypes:
SUCCESS = "success"
EXERCISE = "exercise"
AVAILABLE_ACTIONS = "available-actions"
AVAILABLE_PATIENTS = "available-patients"

class ClosureCodes:
UNKNOWN = 0
NOT_AUTHENTICATED = 401

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.exercise_code = ""
self.exercise_frontend_id = ""
self.exercise = None
self.REQUESTS_MAP = {}
self.user = None
Expand Down Expand Up @@ -152,42 +153,43 @@ def send_exercise_event(self, event):
self._send_exercise(exercise=exercise)

def _send_exercise(self, exercise):
patient, _ = PatientInstance.objects.get_or_create(
name="Max Mustermann", exercise=self.exercise, patient_id=2
self.send_event(
self.OutgoingMessageTypes.EXERCISE,
exercise=ExerciseSerializer(exercise).data,
)
exercise_object = {
"exercise": {
"exerciseId": exercise.exerciseId,
"areas": [
{
"areaName": "X",
"patients": [
{
"patientId": patient.patient_id,
"patientName": patient.name,
"patientCode": 0,
"triage": patient.triage,
}
],
"personnel": [{"personnelId": 0, "personnelName": "X"}],
"material": [{"materialId": 0, "materialName": "X"}],
}
],
}
}
self.send_event(self.OutgoingMessageTypes.EXERCISE, exercise=exercise_object)

def send_available_actions(self):
actions = Action.objects.all()
actions = [
json.dumps(
{
"actionId": action.id,
"actionName": action.name,
"actionCategory": action.category,
}
)
{
"actionName": action.name,
"actionCategory": action.category,
}
for action in actions
]
actions = json.dumps({"actions": actions})
self.send_event(self.OutgoingMessageTypes.AVAILABLE_ACTIONS, availableActions=actions)
self.send_event(
self.OutgoingMessageTypes.AVAILABLE_ACTIONS, availableActions=actions
)

def send_available_patients(self):
patientsInformation = PatientInformation.objects.all()
availablePatients = [
{
"code": patient.code,
"personalDetails": patient.personal_details,
"injury": patient.injury,
"biometrics": patient.biometrics,
"triage": patient.triage,
"consecutiveUniqueNumber": patient.consecutive_unique_number,
"mobility": patient.mobility,
"preexistingIllnesses": patient.preexisting_illnesses,
"permanentMedication": patient.permanent_medication,
"currentCaseHistory": patient.current_case_history,
"pretreatment": patient.pretreatment,
}
for patient in patientsInformation
]
self.send_event(
self.OutgoingMessageTypes.AVAILABLE_PATIENTS,
availablePatients=availablePatients,
)
Loading

0 comments on commit 3f88906

Please sign in to comment.