Exemplo n.º 1
0
    def _create_token(self, task):
        token = create_token(task)
        try:
            class_conf = settings.TASK_SETTINGS.get(
                self.task_type, settings.DEFAULT_TASK_SETTINGS)

            # will throw a key error if the token template has not
            # been specified
            email_conf = class_conf['emails']['token']
            send_stage_email(task, email_conf, token)
            return {'notes': ['created token']}, 200
        except KeyError as e:
            import traceback
            trace = traceback.format_exc()
            self.logger.critical(
                ("(%s) - Exception escaped! %s\nTrace: \n%s") %
                (timezone.now(), e, trace))
            notes = {
                'errors': [("Error: '%s' while sending " + "token. See task " +
                            "itself for details.") % e]
            }
            create_notification(task, notes, error=True)

            response_dict = {
                'errors': [
                    "Error: Something went wrong on the " +
                    "server. It will be looked into shortly."
                ]
            }
            return response_dict, 500
Exemplo n.º 2
0
    def post(self, request, format=None):
        """
        Reissue a token for an approved task.

        Clears other tokens for it.
        """
        uuid = request.data.get('task', None)
        if uuid is None:
            return Response(
                {'errors': {
                    'task': [
                        "This field is required.",
                    ]
                }},
                status=400)
        try:
            if 'admin' in request.keystone_user['roles']:
                task = Task.objects.get(uuid=uuid)
            else:
                task = Task.objects.get(
                    uuid=uuid, project_id=request.keystone_user['project_id'])
        except Task.DoesNotExist:
            return Response({'errors': ['No task with this id.']}, status=404)

        if task.completed:
            return Response(
                {'errors': ['This task has already been completed.']},
                status=400)

        if task.cancelled:
            return Response({'errors': ['This task has been cancelled.']},
                            status=400)

        if not task.approved:
            return Response({'errors': ['This task has not been approved.']},
                            status=400)

        for token in task.tokens:
            token.delete()

        token = create_token(task)
        try:
            class_conf = settings.TASK_SETTINGS.get(
                task.task_type, settings.DEFAULT_TASK_SETTINGS)

            # will throw a key error if the token template has not
            # been specified
            email_conf = class_conf['emails']['token']
            send_stage_email(task, email_conf, token)
        except KeyError as e:
            return self._handle_task_error(e,
                                           task,
                                           "while sending token",
                                           return_response=True)
        return Response({'notes': ['Token reissued.']}, status=200)
Exemplo n.º 3
0
    def post(self, request, id, format=None):
        """
        Ensures the required fields are present,
        will then pass those to the actions via the submit
        function.
        """
        try:
            token = Token.objects.get(token=id)
            if token.expires < timezone.now():
                token.delete()
                token = Token.objects.get(token=id)
        except Token.DoesNotExist:
            return Response(
                {'errors': ['This token does not exist or has expired.']},
                status=404)

        if token.task.completed:
            return Response(
                {'errors': ['This task has already been completed.']},
                status=400)

        if token.task.cancelled:
            return Response({'errors': ['This task has been cancelled.']},
                            status=400)

        if token.expires < timezone.now():
            token.delete()
            return Response({'errors': ['This token has expired.']},
                            status=400)

        required_fields = set()
        actions = []
        for action in token.task.actions:
            a = action.get_action()
            actions.append(a)
            for field in a.token_fields:
                required_fields.add(field)

        errors = {}
        data = {}

        for field in required_fields:
            try:
                data[field] = request.data[field]
            except KeyError:
                errors[field] = [
                    "This field is required.",
                ]
            except TypeError:
                errors = [
                    "Improperly formated json. " +
                    "Should be a key-value object.",
                ]
                break

        if errors:
            return Response({"errors": errors}, status=400)

        for action in actions:
            try:
                action.submit(data)
            except Exception as e:
                notes = {
                    'errors': [("Error: '%s' while submitting task. " +
                                "See task itself for details.") % e],
                    'task':
                    token.task.uuid
                }
                create_notification(token.task, notes)

                import traceback
                trace = traceback.format_exc()
                self.logger.critical(
                    ("(%s) - Exception escaped! %s\n" + "Trace: \n%s") %
                    (timezone.now(), e, trace))

                response_dict = {
                    'errors': [
                        "Error: Something went wrong on the server. " +
                        "It will be looked into shortly."
                    ]
                }
                return Response(response_dict, status=500)

        token.task.completed = True
        token.task.completed_on = timezone.now()
        token.task.save()
        token.delete()

        # Sending confirmation email:
        class_conf = settings.TASK_SETTINGS.get(token.task.task_type,
                                                settings.DEFAULT_TASK_SETTINGS)
        email_conf = class_conf.get('emails', {}).get('completed', None)
        send_stage_email(token.task, email_conf)

        return Response({'notes': ["Token submitted successfully."]},
                        status=200)
Exemplo n.º 4
0
    def post(self, request, format=None):
        """
        Reissue a token for an approved task.

        Clears other tokens for it.
        """
        uuid = request.data.get('task', None)
        if uuid is None:
            return Response({'task': [
                "This field is required.",
            ]},
                            status=400)
        try:
            if 'admin' in request.keystone_user['roles']:
                task = Task.objects.get(uuid=uuid)
            else:
                task = Task.objects.get(
                    uuid=uuid, project_id=request.keystone_user['project_id'])
        except Task.DoesNotExist:
            return Response({'errors': ['No task with this id.']}, status=404)

        if task.completed:
            return Response(
                {'errors': ['This task has already been completed.']},
                status=400)

        if task.cancelled:
            return Response({'errors': ['This task has been cancelled.']},
                            status=400)

        if not task.approved:
            return Response({'errors': ['This task has not been approved.']},
                            status=400)

        for token in task.tokens:
            token.delete()

        token = create_token(task)
        try:
            class_conf = settings.TASK_SETTINGS.get(
                task.task_type, settings.DEFAULT_TASK_SETTINGS)

            # will throw a key error if the token template has not
            # been specified
            email_conf = class_conf['emails']['token']
            send_stage_email(task, email_conf, token)
        except KeyError as e:
            notes = {
                'errors': [("Error: '%(error)s' while sending token. " +
                            "See registration itself for details.") % {
                                'error': e
                            }],
                'task':
                task.uuid
            }
            create_notification(task, notes)

            import traceback
            trace = traceback.format_exc()
            self.logger.critical(
                ("(%s) - Exception escaped!" + " %s\n Trace: \n%s") %
                (timezone.now(), e, trace))

            response_dict = {
                'errors': [
                    "Error: Something went wrong on the " +
                    "server. It will be looked into shortly."
                ]
            }
            return Response(response_dict, status=500)
        return Response({'notes': ['Token reissued.']}, status=200)
Exemplo n.º 5
0
    def post(self, request, uuid, format=None):
        """
        Will approve the Task specified,
        followed by running the post_approve actions
        and if valid will setup and create a related token.
        """
        try:
            task = Task.objects.get(uuid=uuid)
        except Task.DoesNotExist:
            return Response({'errors': ['No task with this id.']}, status=404)

        try:
            if request.data.get('approved') is not True:
                return Response(
                    {'approved': ["this is a required boolean field."]},
                    status=400)
        except ParseError:
            return Response(
                {'approved': ["this is a required boolean field."]},
                status=400)

        if task.completed:
            return Response(
                {'errors': ['This task has already been completed.']},
                status=400)

        if task.cancelled:
            return Response({'errors': ['This task has been cancelled.']},
                            status=400)

        # we check that the task is valid before approving it:
        valid = True
        for action in task.actions:
            if not action.valid:
                valid = False

        if not valid:
            return Response(
                {
                    'errors': [
                        'Cannot approve an invalid task. ' +
                        'Update data and rerun pre_approve.'
                    ]
                },
                status=400)

        # We approve the task before running actions,
        # that way if something goes wrong we know if it was approved,
        # when it was approved, and who approved it last. Subsequent
        # reapproval attempts overwrite previous approved_by/on.
        task.approved = True
        task.approved_by = request.keystone_user
        task.approved_on = timezone.now()
        task.save()

        need_token = False
        valid = True

        actions = []

        for action in task.actions:
            act_model = action.get_action()
            actions.append(act_model)
            try:
                act_model.post_approve()
            except Exception as e:
                notes = {
                    'errors': [("Error: '%s' while approving task. " +
                                "See task itself for details.") % e],
                    'task':
                    task.uuid
                }
                create_notification(task, notes)

                import traceback
                trace = traceback.format_exc()
                self.logger.critical(
                    ("(%s) - Exception escaped! %s\n" + "Trace: \n%s") %
                    (timezone.now(), e, trace))

                return Response(notes, status=500)

            if not action.valid:
                valid = False
            if action.need_token:
                need_token = True

        if valid:
            if need_token:
                token = create_token(task)
                try:
                    class_conf = settings.TASK_SETTINGS.get(
                        task.task_type, settings.DEFAULT_TASK_SETTINGS)

                    # will throw a key error if the token template has not
                    # been specified
                    email_conf = class_conf['emails']['token']
                    send_stage_email(task, email_conf, token)
                    return Response({'notes': ['created token']}, status=200)
                except KeyError as e:
                    notes = {
                        'errors':
                        [("Error: '%s' while sending " + "token. See task " +
                          "itself for details.") % e],
                        'task':
                        task.uuid
                    }
                    create_notification(task, notes)

                    import traceback
                    trace = traceback.format_exc()
                    self.logger.critical(
                        ("(%s) - Exception escaped!" + " %s\n Trace: \n%s") %
                        (timezone.now(), e, trace))

                    response_dict = {
                        'errors': [
                            "Error: Something went wrong on the " +
                            "server. It will be looked into shortly."
                        ]
                    }
                    return Response(response_dict, status=500)
            else:
                for action in actions:
                    try:
                        action.submit({})
                    except Exception as e:
                        notes = {
                            'errors':
                            [("Error: '%s' while submitting " +
                              "task. See task " + "itself for details.") % e],
                            'task':
                            task.uuid
                        }
                        create_notification(task, notes)

                        import traceback
                        trace = traceback.format_exc()
                        self.logger.critical(
                            ("(%s) - Exception escaped!" + " %s\n Trace: \n%s")
                            % (timezone.now(), e, trace))

                        return Response(notes, status=500)

                task.completed = True
                task.completed_on = timezone.now()
                task.save()

                # Sending confirmation email:
                class_conf = settings.TASK_SETTINGS.get(
                    task.task_type, settings.DEFAULT_TASK_SETTINGS)
                email_conf = class_conf.get('emails',
                                            {}).get('completed', None)
                send_stage_email(task, email_conf)

                return Response({'notes': ["Task completed successfully."]},
                                status=200)
        return Response({'errors': ['actions invalid']}, status=400)
Exemplo n.º 6
0
    def approve(self, request, task):
        """
        Approves the task and runs the post_approve steps.
        Will create a token if required, otherwise will run the
        submit steps.
        """

        # We approve the task before running actions,
        # that way if something goes wrong we know if it was approved,
        # when it was approved, and who approved it.
        task.approved = True
        task.approved_on = timezone.now()
        task.approved_by = request.keystone_user
        task.save()

        action_models = task.actions
        actions = [act.get_action() for act in action_models]
        need_token = False

        valid = all([act.valid for act in actions])
        if not valid:
            return {'errors': ['actions invalid']}, 400

        # post_approve all actions
        for action in actions:
            try:
                action.post_approve()
            except Exception as e:
                import traceback
                trace = traceback.format_exc()
                self.logger.critical(
                    ("(%s) - Exception escaped! %s\nTrace: \n%s") %
                    (timezone.now(), e, trace))
                notes = {
                    'errors': [("Error: '%s' while approving task. " +
                                "See task itself for details.") % e]
                }
                create_notification(task, notes, error=True)

                response_dict = {
                    'errors': [
                        "Error: Something went wrong on the server. " +
                        "It will be looked into shortly."
                    ]
                }
                return response_dict, 500

        valid = all([act.valid for act in actions])
        if not valid:
            return {'errors': ['actions invalid']}, 400

        need_token = any([act.need_token for act in actions])
        if need_token:
            return self._create_token(task)

        # submit all actions
        for action in actions:
            try:
                action.submit({})
            except Exception as e:
                import traceback
                trace = traceback.format_exc()
                self.logger.critical(
                    ("(%s) - Exception escaped! %s\nTrace: \n%s") %
                    (timezone.now(), e, trace))
                notes = {
                    'errors': [("Error: '%s' while submitting " +
                                "task. See task " + "itself for details.") % e]
                }
                create_notification(task, notes, error=True)

                response_dict = {
                    'errors': [
                        "Error: Something went wrong on the " +
                        "server. It will be looked into shortly."
                    ]
                }
                return response_dict, 500

        task.completed = True
        task.completed_on = timezone.now()
        task.save()

        # Sending confirmation email:
        class_conf = settings.TASK_SETTINGS.get(self.task_type,
                                                settings.DEFAULT_TASK_SETTINGS)
        email_conf = class_conf.get('emails', {}).get('completed', None)
        send_stage_email(task, email_conf)
        return {'notes': ["Task completed successfully."]}, 200
Exemplo n.º 7
0
    def process_actions(self, request):
        """
        Will ensure the request data contains the required data
        based on the action serializer, and if present will create
        a Task and the linked actions, attaching notes
        based on running of the the pre_approve validation
        function on all the actions.

        If during the pre_approve step at least one of the actions
        sets auto_approve to True, and none of them set it to False
        the approval steps will also be run.
        """
        class_conf = settings.TASK_SETTINGS.get(self.task_type,
                                                settings.DEFAULT_TASK_SETTINGS)

        # Action serializers
        action_serializer_list = self._instantiate_action_serializers(
            request, class_conf)

        if isinstance(action_serializer_list, tuple):
            return action_serializer_list

        hash_key = create_task_hash(self.task_type, action_serializer_list)

        # Handle duplicates
        duplicate_error = self._handle_duplicates(class_conf, hash_key)
        if duplicate_error:
            return duplicate_error

        # Instantiate Task
        ip_address = request.META['REMOTE_ADDR']
        keystone_user = request.keystone_user
        try:
            task = Task.objects.create(ip_address=ip_address,
                                       keystone_user=keystone_user,
                                       project_id=keystone_user['project_id'],
                                       task_type=self.task_type,
                                       hash_key=hash_key)
        except KeyError:
            task = Task.objects.create(ip_address=ip_address,
                                       keystone_user=keystone_user,
                                       task_type=self.task_type,
                                       hash_key=hash_key)
        task.save()

        # Instantiate actions with serializers
        for i, action in enumerate(action_serializer_list):
            data = action['serializer'].validated_data

            # construct the action class
            action_instance = action['action'](data=data, task=task, order=i)

            try:
                action_instance.pre_approve()
            except Exception as e:
                import traceback
                trace = traceback.format_exc()
                self.logger.critical(
                    ("(%s) - Exception escaped! %s\nTrace: \n%s") %
                    (timezone.now(), e, trace))
                notes = {
                    'errors': [("Error: '%s' while setting up task. " +
                                "See task itself for details.") % e]
                }
                create_notification(task, notes, error=True)

                response_dict = {
                    'errors': [
                        "Error: Something went wrong on the server. " +
                        "It will be looked into shortly."
                    ]
                }
                return response_dict, 200

        # send initial confirmation email:
        email_conf = class_conf.get('emails', {}).get('initial', None)
        send_stage_email(task, email_conf)

        action_models = task.actions
        approve_list = [act.get_action().auto_approve for act in action_models]

        # TODO(amelia): It would be nice to explicitly test this, however
        #               currently we don't have the right combinations of
        #               actions to allow for it.
        if False in approve_list:
            can_auto_approve = False
        elif True in approve_list:
            can_auto_approve = True
        else:
            can_auto_approve = False

        if can_auto_approve:
            task_name = self.__class__.__name__
            self.logger.info("(%s) - AutoApproving %s request." %
                             (timezone.now(), task_name))
            approval_data, status = self.approve(request, task)
            # Additional information that would be otherwise expected
            approval_data['task'] = task
            approval_data['auto_approved'] = True
            return approval_data, status

        return {'task': task}, 200
Exemplo n.º 8
0
    def post(self, request, id, format=None):
        """
        Ensures the required fields are present,
        will then pass those to the actions via the submit
        function.
        """
        try:
            token = Token.objects.get(token=id)
            if token.expires < timezone.now():
                token.delete()
                token = Token.objects.get(token=id)
        except Token.DoesNotExist:
            return Response(
                {'errors': ['This token does not exist or has expired.']},
                status=404)

        if token.task.completed:
            return Response(
                {'errors': ['This task has already been completed.']},
                status=400)

        if token.task.cancelled:
            return Response({'errors': ['This task has been cancelled.']},
                            status=400)

        required_fields = set()
        actions = []
        for action in token.task.actions:
            a = action.get_action()
            actions.append(a)
            for field in a.token_fields:
                required_fields.add(field)

        errors = {}
        data = {}

        for field in required_fields:
            try:
                data[field] = request.data[field]
            except KeyError:
                errors[field] = [
                    "This field is required.",
                ]
            except TypeError:
                errors = [
                    "Improperly formated json. "
                    "Should be a key-value object."
                ]
                break

        if errors:
            return Response({"errors": errors}, status=400)

        valid = True
        for action in actions:
            try:
                action.submit(data)

                if not action.valid:
                    valid = False

            except Exception as e:
                return self._handle_task_error(e,
                                               token.task,
                                               "while submiting task",
                                               return_response=True)

        if not valid:
            return Response({"errors": ["Actions invalid"]}, status=400)

        token.task.completed = True
        token.task.completed_on = timezone.now()
        token.task.save()
        token.delete()

        # Sending confirmation email:
        class_conf = settings.TASK_SETTINGS.get(token.task.task_type,
                                                settings.DEFAULT_TASK_SETTINGS)
        email_conf = class_conf.get('emails', {}).get('completed', None)
        send_stage_email(token.task, email_conf)

        return Response({'notes': ["Token submitted successfully."]},
                        status=200)
Exemplo n.º 9
0
    def post(self, request, uuid, format=None):
        """
        Will approve the Task specified,
        followed by running the post_approve actions
        and if valid will setup and create a related token.
        """
        try:
            task = Task.objects.get(uuid=uuid)
        except Task.DoesNotExist:
            return Response({'errors': ['No task with this id.']}, status=404)

        try:
            if request.data.get('approved') is not True:
                return Response(
                    {'approved': ["this is a required boolean field."]},
                    status=400)
        except ParseError:
            return Response(
                {'approved': ["this is a required boolean field."]},
                status=400)

        if task.completed:
            return Response(
                {'errors': ['This task has already been completed.']},
                status=400)

        if task.cancelled:
            return Response({'errors': ['This task has been cancelled.']},
                            status=400)

        # we check that the task is valid before approving it:
        valid = True
        for action in task.actions:
            if not action.valid:
                valid = False

        if not valid:
            return Response(
                {
                    'errors': [
                        'Cannot approve an invalid task. '
                        'Update data and rerun pre_approve.'
                    ]
                },
                status=400)

        if task.approved:
            # Expire previously in use tokens
            Token.objects.filter(task=task.uuid).delete()

        # We approve the task before running actions,
        # that way if something goes wrong we know if it was approved,
        # when it was approved, and who approved it last. Subsequent
        # reapproval attempts overwrite previous approved_by/on.
        task.approved = True
        task.approved_by = request.keystone_user
        task.approved_on = timezone.now()
        task.save()

        need_token = False
        valid = True

        actions = []

        for action in task.actions:
            act_model = action.get_action()
            actions.append(act_model)
            try:
                act_model.post_approve()
            except Exception as e:
                return self._handle_task_error(e,
                                               task,
                                               "while approving task",
                                               return_response=True)

            if not action.valid:
                valid = False
            if action.need_token:
                need_token = True

        if valid:
            if need_token:
                token = create_token(task)
                try:
                    class_conf = settings.TASK_SETTINGS.get(
                        task.task_type, settings.DEFAULT_TASK_SETTINGS)

                    # will throw a key error if the token template has not
                    # been specified
                    email_conf = class_conf['emails']['token']
                    send_stage_email(task, email_conf, token)
                    return Response({'notes': ['created token']}, status=200)
                except KeyError as e:
                    return self._handle_task_error(e,
                                                   task,
                                                   "while sending token",
                                                   return_response=True)
            else:
                for action in actions:
                    try:
                        action.submit({})
                    except Exception as e:
                        return self._handle_task_error(e,
                                                       task,
                                                       "while submitting task",
                                                       return_response=True)

                task.completed = True
                task.completed_on = timezone.now()
                task.save()

                # Sending confirmation email:
                class_conf = settings.TASK_SETTINGS.get(
                    task.task_type, settings.DEFAULT_TASK_SETTINGS)
                email_conf = class_conf.get('emails',
                                            {}).get('completed', None)
                send_stage_email(task, email_conf)

                return Response({'notes': ["Task completed successfully."]},
                                status=200)
        return Response({'errors': ['actions invalid']}, status=400)