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
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)
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)
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)
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)
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
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
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)
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)