Completed
Push — master ( 313cfe...2c16e2 )
by Paolo
21s queued 14s
created

submissions.tasks.SubmissionTaskMixin.on_failure()   A

Complexity

Conditions 2

Size

Total Lines 32
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 18
dl 0
loc 32
rs 9.5
c 0
b 0
f 0
cc 2
nop 6
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
"""
4
Created on Tue Jul  9 16:10:06 2019
5
6
@author: Paolo Cozzi <[email protected]>
7
"""
8
9
import logging
10
11
from django.utils import timezone
12
13
from common.constants import ERROR, NEED_REVISION
14
from common.tasks import NotifyAdminTaskMixin
15
from image_app.models import Submission
16
from validation.helpers import construct_validation_message
17
18
from .helpers import send_message
19
20
# Get an instance of a logger
21
logger = logging.getLogger(__name__)
22
23
24
# HINT: should I move all this stuff into image_app module?
25
class SubmissionTaskMixin():
26
    """A mixin to extend Task to support UID Submission objects"""
27
28
    action = None
29
    max_body_size = 5000
30
31
    def get_uid_submission(self, submission_id):
32
        """Get a UID Submission instance from an id
33
34
        Args:
35
            submission_id (int): the submission id
36
37
        Returns:
38
            :py:class:`Submission`: a UID submission instance
39
        """
40
41
        return Submission.objects.get(pk=submission_id)
42
43
    # extract a generic send_message for all modules which need it
44
    def send_message(self, submission_obj, construct_message=False):
45
        """
46
        Update submission.status and submission message using django
47
        channels
48
49
        Args:
50
            submission_obj (image_app.models.Submission): an UID submission
51
            object
52
            construct_message (bool): construct validation message or not
53
        """
54
55
        if construct_message is True:
56
            send_message(
57
                submission_obj, construct_validation_message(submission_obj)
58
            )
59
        else:
60
            send_message(submission_obj)
61
62
    def update_submission_status(
63
            self, submission_obj, status, message, construct_message=False):
64
        """Mark submission with status, then send message
65
66
        Args:
67
            submission_obj (image_app.models.Submission): an UID submission
68
            object
69
            status (int): a :py:class:`common.constants.STATUSES` value
70
            message (str): the message to send
71
            construct_message (bool): construct validation message or not
72
        """
73
74
        submission_obj.status = status
75
        submission_obj.message = message
76
        submission_obj.save()
77
78
        # send async message
79
        self.send_message(submission_obj, construct_message)
80
81
    def mail_to_owner(self, submission_obj, subject, body):
82
        # truncate message body if necessary
83
        if len(body) > self.max_body_size:
84
            body = body[:self.max_body_size] + "...[truncated]"
85
86
        submission_obj.owner.email_user(subject, body)
87
88
    def on_failure(self, exc, task_id, args, kwargs, einfo):
89
        """Override the default on_failure method"""
90
91
        # call base class
92
        super().on_failure(exc, task_id, args, kwargs, einfo)
93
94
        # get submission object
95
        if 'uid_submission_id' in kwargs:
96
            submission_id = kwargs['uid_submission_id']
97
98
        else:
99
            submission_id = args[0]
100
        submission_obj = self.get_uid_submission(submission_id)
101
102
        # mark submission with ERROR and send message
103
        self.update_submission_status(
104
            submission_obj,
105
            ERROR,
106
            "Error in %s: %s" % (self.action, str(exc))
107
        )
108
109
        # send a mail to the user with the stacktrace (einfo)
110
        subject = "Error in %s for submission %s" % (
111
            self.action, submission_id)
112
        body = (
113
            "Something goes wrong with %s. Please report "
114
            "this to InjectTool team\n\n %s" % (
115
                self.action,
116
                str(einfo))
117
        )
118
119
        self.mail_to_owner(submission_obj, subject, body)
120
121
122
class ImportGenericTaskMixin(SubmissionTaskMixin, NotifyAdminTaskMixin):
123
    """A mixing used to import datasource into UID"""
124
125
    action = None
126
127
    def run(self, submission_id):
128
        """a function to upload data into UID"""
129
130
        logger.info(
131
            "Start %s for submission: %s" % (self.action, submission_id))
132
133
        # get a submission object (from SubmissionTaskMixin)
134
        submission_obj = self.get_uid_submission(submission_id)
135
136
        # upload data into UID with the proper method (defined in child class)
137
        status = self.import_data_from_file(submission_obj)
138
139
        # if something went wrong, uploaded_cryoweb has token the exception
140
        # ad update submission.message field
141
        if status is False:
142
            message = "Error in %s" % (self.action)
143
            logger.error(message)
144
145
            # this a failure in my import, not the task itself
146
            return message
147
148
        else:
149
            message = "%s completed for submission: %s" % (
150
                self.action, submission_id)
151
152
            # debug
153
            logger.info(message)
154
155
            # always return something
156
            return "success"
157
158
159
class BatchUpdateMixin(SubmissionTaskMixin):
160
    """Mixin to do batch update of fields to fix validation"""
161
162
    item_cls = None
163
164
    def batch_update(self, submission_id, ids, attribute):
165
        for id_, value in ids.items():
166
            if value == '' or value == 'None':
167
                value = None
168
169
            item_object = self.item_cls.objects.get(pk=id_)
170
171
            if getattr(item_object, attribute) != value:
172
                setattr(item_object, attribute, value)
173
                item_object.save()
174
175
                # update name object
176
                item_object.name.last_changed = timezone.now()
177
                item_object.name.save()
178
179
        # get a submission object (from SubmissionTaskMixin)
180
        submission_obj = self.get_uid_submission(submission_id)
181
182
        # mark submission with NEED_REVISION and send message
183
        self.update_submission_status(
184
            submission_obj,
185
            NEED_REVISION,
186
            "Data updated, try to rerun validation",
187
            construct_message=True
188
        )
189