diff -r cd5e8fb64b74 -r 56850f5c73f6 src/protocols/models/managers.py --- /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