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