src/protocols/models/managers.py
changeset 142 56850f5c73f6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocols/models/managers.py	Wed Jul 18 17:32:09 2018 +0200
@@ -0,0 +1,162 @@
+import logging
+import uuid
+
+from django.apps import apps
+from django.core.exceptions import ValidationError
+from django.db import models, transaction
+
+logger = logging.getLogger(__name__)
+
+class ProtocolManager(models.Manager):
+    #TODO: check id must be the same
+    #TODO: check owner must be the same
+    @transaction.atomic
+    def create_new_revision(self, protocol_id, revision_def, app):
+        # lock the protocol
+        owner = revision_def.get('owner', None)
+        if not owner:
+            raise ValidationError("Must have an owner")
+
+        last_revision_modified = False
+
+        if protocol_id is None:
+            protocol = self.model(app=app, owner=owner)
+            protocol.save()
+            protocol_revision_model = apps.get_model(app_label='protocols', model_name='ProtocolRevision')
+            last_revision = protocol_revision_model(protocol=protocol)
+            last_revision_modified = True
+        else:
+            protocol = self.select_for_update().get(ext_id=protocol_id, app=app)
+            revision_nb = revision_def.get('version')
+            last_revision = protocol.last_revision()
+            if last_revision is not None and (revision_nb is None or revision_nb != last_revision.version):
+                raise ValidationError("Bad protocol revision number when creating new revision")
+
+
+        # create new protocol revision update protocol revision title and description
+
+        title = revision_def.get('title', None)
+        description = revision_def.get('description', None)
+
+        last_revision_modified = last_revision_modified or \
+            (title != last_revision.title or description != last_revision.description)
+
+        metacategory_model = apps.get_model(app_label='protocols', model_name='Metacategory')
+        new_metacategories = [metacategory_model.objects.get_or_create_revision(app, **metacategory_def) for metacategory_def in revision_def.get('metacategories', [])]
+
+        if not last_revision_modified:
+            new_metacategories_ids = { mc.ext_id for mc in new_metacategories }
+            old_metacategories_ids = { mc.ext_id for mc in last_revision.metacategories.all() }
+
+            last_revision_modified = (new_metacategories_ids != old_metacategories_ids )
+
+            if last_revision_modified:
+                logger.debug("metacategaories modified %r, %r", new_metacategories_ids, old_metacategories_ids)
+
+
+        if last_revision_modified:
+            last_revision.pk = None
+            last_revision.ext_id = uuid.uuid4()
+            if title is not None:
+                last_revision.title = title
+            if description is not None:
+                last_revision.description = description
+            last_revision.save()
+
+            last_revision.metacategories.add(*new_metacategories)
+
+        return last_revision
+
+    @transaction.atomic
+    def create_from_default(self, title, description, owner, app):
+        metacategory_model = apps.get_model(app_label='protocols', model_name='Metacategory')
+        default_metacategories = metacategory_model.objects.filter(is_default=True, app=app)
+
+        protocol = self.create(app=app, owner=owner)
+
+        protocol_revision_model = apps.get_model(app_label='protocols', model_name='ProtocolRevision')
+
+        protocol_revision = protocol_revision_model.objects.create(protocol=protocol, title=title, description=description)
+
+        protocol_revision.metacategories.set([mc.revisions.all().last() for mc in default_metacategories])
+        protocol_revision.save()
+
+        return protocol
+
+
+class MetacategoryManager(models.Manager):
+
+
+    @transaction.atomic
+    def create_with_revision(self, *args, **kwargs):
+        instance = self.create(*args, **kwargs)
+        metacategory_revision_model = apps.get_model(app_label='protocols', model_name='MetacategoryRevision')
+        revision = metacategory_revision_model.objects.create(base=instance, **{k : kwargs.get(k) for k in ['title', 'label', 'description', 'color', 'has_comment']})
+
+        return instance
+
+
+    @transaction.atomic
+    def get_or_create_revision(self, app, **kwargs):
+
+        # cases :
+        # id: none, base: none
+        #   -> create metacategory + revision
+        # id: <>, base: none
+        #   -> error
+        # id: <>, base: <>
+        #   -> compare filed values
+        #   -> if same : return current instance, if not same : create new revision
+        # id: none, base: <>
+        #   -> compare to last revision. if different, create new revision else return revision
+        id = kwargs.get('id')
+        base = kwargs.get('base')
+
+        if id is not None and base is None:
+            raise ValidationError("Id is not empty and base is empty")
+
+        metacategory = None
+        metacategory_created = False
+        if base is None:
+            metacategory_created = True
+            metacategory = self.model(
+                app=app,
+                title=kwargs.get('title'),
+                label=kwargs.get('label'),
+                description=kwargs.get('description'),
+                color=kwargs.get('color'),
+                has_comment=kwargs.get('has_comment', False),
+                is_default=False
+            )
+            metacategory.save()
+        else:
+            metacategory = self.get(ext_id=base, app=app)
+
+        revision = None
+        metacategory_revision_model = apps.get_model(app_label='protocols', model_name='MetacategoryRevision')
+
+        if id is None and not metacategory_created:
+            revision = metacategory.last_revision()
+        elif not metacategory_created:
+            revision = metacategory_revision_model.objects.get(ext_id=id)
+
+        must_create_revision = (revision is None)
+        if revision is not None:
+            must_create_revision = \
+                (revision.title != kwargs.get('title')) or \
+                (revision.label != kwargs.get('label')) or \
+                (revision.description != kwargs.get('description')) or \
+                (revision.color != kwargs.get('color')) or \
+                (revision.has_comment != kwargs.get('has_comment', False))
+
+        if must_create_revision:
+            revision = metacategory_revision_model.objects.create(
+                base=metacategory,
+                title=kwargs.get('title'),
+                label=kwargs.get('label'),
+                description=kwargs.get('description'),
+                color=kwargs.get('color'),
+                has_comment=kwargs.get('has_comment', False)
+            )
+
+        return revision