src/protocols/models/managers.py
author ymh <ymh.work@gmail.com>
Wed, 18 Jul 2018 17:32:09 +0200
changeset 142 56850f5c73f6
permissions -rw-r--r--
- upgrade libraries - python 3.7 compatibility - First protocol management implementation

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