signals.py 7.54 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :

###############################################################################
#                                                                             #
# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/           #
# Contact: beat.support@idiap.ch                                              #
#                                                                             #
# This file is part of the beat.web module of the BEAT platform.              #
#                                                                             #
# Commercial License Usage                                                    #
# Licensees holding valid commercial BEAT licenses may use this file in       #
# accordance with the terms contained in a written agreement between you      #
# and Idiap. For further information contact tto@idiap.ch                     #
#                                                                             #
# Alternatively, this file may be used under the terms of the GNU Affero      #
# Public License version 3 as published by the Free Software and appearing    #
# in the file LICENSE.AGPL included in the packaging of this file.            #
# The BEAT platform is distributed in the hope that it will be useful, but    #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY  #
# or FITNESS FOR A PARTICULAR PURPOSE.                                        #
#                                                                             #
# You should have received a copy of the GNU Affero Public License along      #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/.           #
#                                                                             #
###############################################################################


from django.db import models
30
from django.dispatch import receiver
31

32
from ..common.utils import annotate_full_name
33
from ..dataformats.models import DataFormat
34
from ..protocoltemplates.models import ProtocolTemplate
35 36 37
from .models import Database
from .models import DatabaseProtocol
from .models import DatabaseSet
38
from .models import DatabaseSetOutput
39 40
from .models import DatabaseSetTemplate
from .models import DatabaseSetTemplateOutput
41 42
from .models import validate_database

43 44 45

@receiver(models.signals.post_delete, sender=Database)
def auto_delete_file_on_delete(sender, instance, **kwargs):
46
    """Deletes file from filesystem when ``Database`` object is deleted."""
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
    if instance.declaration_file:
        instance.declaration_file.delete(save=False)

    if instance.source_code_file:
        instance.source_code_file.delete(save=False)

    if instance.description_file:
        instance.description_file.delete(save=False)


@receiver(models.signals.pre_save, sender=Database)
def auto_delete_file_on_change(sender, instance, **kwargs):
    """Deletes file from filesystem when ``Database`` object is changed."""

    if not instance.pk:
        return False

    try:
        old_file = Database.objects.get(pk=instance.pk).declaration_file
    except Database.DoesNotExist:
        return False

    if old_file != instance.declaration_file:
        old_file.delete(save=False)

    try:
        old_code = Database.objects.get(pk=instance.pk).source_code_file
    except Database.DoesNotExist:
        return False

    if old_code != instance.source_code_file:
        old_code.delete(save=False)

    try:
        old_descr = Database.objects.get(pk=instance.pk).description_file
    except Database.DoesNotExist:
        return False

    if old_descr != instance.description_file:
        old_descr.delete(save=False)


@receiver(models.signals.post_save, sender=Database)
def refresh_protocols(sender, instance, **kwargs):
    """Refreshes changed protocols"""

    try:
94 95
        core = validate_database(instance.declaration)
        core.name = instance.fullname()
96 97

        protocols = DatabaseProtocol.objects.filter(
98
            database__name=instance.name, database__version=instance.version,
Philip ABBET's avatar
Philip ABBET committed
99
        )
100 101

        existing = set((k.name, k.set_template_basename()) for k in protocols)
102
        new_objects = set([(k, v["template"]) for k, v in core.protocols.items()])
103 104 105 106 107

        for protocol_name, template in existing - new_objects:
            # notice: no need to worry, this will clean-up all the rest
            protocols.get(name__iexact=protocol_name).delete()

108
        json_protocols = dict([(k, v) for k, v in core.protocols.items()])
109 110 111 112 113 114 115

        for protocol_name, template in new_objects - existing:
            protocol = DatabaseProtocol(name=protocol_name, database=instance)
            protocol.save()

            json_protocol = json_protocols[protocol_name]

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
            set_data_list = []
            for set_name, set_attr in core.sets(protocol_name).items():
                set_data = {
                    # V1 has a dedicated template name while V2 has one unique
                    # name
                    "template": set_attr.get("template", set_name),
                    "name": set_attr["name"],
                    "outputs": set_attr["outputs"],
                }

                set_data_list.append(set_data)

            for set_attr in set_data_list:

                template_name = json_protocol["template"]
                try:
                    protocol_template = annotate_full_name(
                        ProtocolTemplate.objects
                    ).get(full_name=template_name)
                except ProtocolTemplate.DoesNotExist:
                    pass
                else:
                    protocol_template.databases.add(instance)

                tset_name = template_name + "__" + set_attr["template"]
141

142 143 144
                dataset_template, _ = DatabaseSetTemplate.objects.get_or_create(
                    name=tset_name
                )
145 146

                # Create the database set
147 148
                dataset, _ = DatabaseSet.objects.get_or_create(
                    name=set_attr["name"], template=dataset_template, protocol=protocol
Philip ABBET's avatar
Philip ABBET committed
149
                )
150

151
                # Create the database set template output
152 153
                for output_name, format_name in set_attr["outputs"].items():
                    if len(format_name.split("/")) != 3:
154
                        raise SyntaxError(
155 156
                            "Dataformat should be named following the "
                            "style `<username>/<format>/<version>', the "
157
                            "value `%s' is not valid" % (format_name,)
Philip ABBET's avatar
Philip ABBET committed
158
                        )
159
                    (author, name, version) = format_name.split("/")
160
                    dataformat = DataFormat.objects.get(
161
                        author__username=author, name=name, version=version,
Philip ABBET's avatar
Philip ABBET committed
162
                    )
163

164 165 166 167
                    (
                        database_template_output,
                        _,
                    ) = DatabaseSetTemplateOutput.objects.get_or_create(
168 169
                        name=output_name,
                        template=dataset_template,
170
                        dataformat=dataformat,
171 172
                    )

173
                    # Create the database set output
174
                    DatabaseSetOutput.objects.get_or_create(
175 176
                        template=database_template_output, set=dataset,
                    )
177

178
    except Exception:
179
        instance.delete()
180 181 182 183 184 185
        raise


@receiver(models.signals.post_delete, sender=DatabaseSet)
def delete_empty_template_sets(sender, **kwargs):

186
    instance = kwargs["instance"]
187
    try:
188 189 190
        if not instance.template.sets.all():
            instance.template.delete()
    except Exception:  # nosec
191
        pass