def create(request): options = request.POST if 'new_item' in options: items = Item.objects.order_by('-id') top_item_id = items and items[0].id or 0 category_id = Category.objects.filter(id=options['category'])[0].id new_item = Item(id=top_item_id + 1, label=options['new_item'], details=options['details'], assigned_to_id=None, validation_id=3, category_id=category_id) new_item.save() return render_to_response('workflow/one_item.html', {'item' : new_item}) if 'new_category' in options: categories = Category.objects.order_by('-id') top_category_id = categories and categories[0].id or 0 orders = Category.objects.order_by('-order') top_order = orders and orders[0].id or 0 new_category = Category(top_category_id + 1, options['new_category'], top_order, options['workflow_id']) new_category.save() return render_to_response('workflow/one_category.html', {'category' : new_category}) if options['new_section']: sections = WorkflowSection.objects.order_by('-id') top_section_id = sections and sections[0].id or 0 new_section = WorkflowSection(top_section_id + 1, options['new_section']) new_section.save() else: new_section = WorkflowSection.objects.filter(label=options['section'])[0] workflows = Workflow.objects.order_by('-id') top_id = workflows and workflows[0].id or 0 new_workflow = Workflow(id=top_id + 1, workflow_section=new_section, label=options['new_workflow']) new_workflow.save() return HttpResponseRedirect(reverse('index'))
def remove_workflow_from_session(request: HttpRequest): """Remove the workflowid, name and number of fows from the session.""" wid = request.session.pop('ontask_workflow_id', None) # If removing workflow from session, mark it as available for sharing if wid: Workflow.unlock_workflow_by_id(wid) request.session.pop('ontask_workflow_name', None) request.session.pop('ontask_workflow_rows', None) request.session.save()
def _render_table_display_page( request: HttpRequest, workflow: Workflow, view: Optional[View], columns, ajax_url: str, ): """Render content of the display page. Function to render the content of the display page taking into account the columns to show and the AJAX url to use to render the table content. :param request: HTTP request :param workflow: Workflow object used to access the data frame :param view: View to use to render the table (or None) :param columns: Columns to display in the page :param ajax_url: URL to invoke to populate the table :return: HTTP Response """ # Create the initial context context = { 'workflow': workflow, 'query_builder_ops': workflow.get_query_builder_ops_as_str(), 'ajax_url': ajax_url, 'views': workflow.views.all(), 'no_actions': workflow.actions.count() == 0, 'vis_scripts': PlotlyHandler.get_engine_scripts(), } # If there is a DF, add the columns if workflow.has_table(): context['columns'] = columns context['column_types'] = str([''] + [ col.data_type for col in columns]) context['columns_datatables'] = [{'data': 'Operations'}] + [ {'data': col.name.replace('.', '\\.')} for col in columns] context['stat_columns'] = workflow.columns.filter(is_key=False) else: context['columns'] = None context['columns_datatables'] = [] # If using a view, add it to the context if view: context['view'] = view return render(request, 'table/display.html', context)
def setUp(self): self.setup_test() self.workflow = Workflow( {"root": [{ "key": "MY_GROUP", "children": [] }]})
def setup_outcome(self, spec, key_values=None): key_values = key_values or {} full_spec = { "spec": spec, "type": "my_outcome", } workflow = Workflow({ "root": [{ "key": "KEY_1", "value": key_values.get("KEY_1", "na"), "children": [ { "key": "KEY_1.1", "value": key_values.get("KEY_1.1", "na"), }, { "key": "KEY_1.2", "value": key_values.get("KEY_1.2", "na"), }, { "key": "KEY_1.3", "value": key_values.get("KEY_1.3", "na"), }, ], "outcome_spec": full_spec, }] }) action = workflow["root"][0].copy() return MyOutcome(action, workflow, full_spec)
def wf_lock_and_update( request: HttpRequest, workflow: Workflow, create_session: Optional[bool] = False, ) -> Workflow: """Lock a workflow and updates the value in the session. :param request: Http request to update :param workflow: Object to store """ workflow.lock(request, create_session) # Update nrows in case it was asynch modified store_workflow_nrows_in_session(request, workflow) return workflow
def get_actions(self, container): actions = Workflow.objects(container=container.id) for action in actions: action.datalab = action.datalab.name serializer = ActionSerializer(actions, many=True) return serializer.data
def sqlconnection_admin_index(request): """ Page to show and handle the SQL connections :param request: Request :return: Render the appropriate page. """ wid = request.session.pop('ontask_workflow_id', None) # If removing workflow from session, mark it as available for sharing if wid: Workflow.unlock_workflow_by_id(wid) request.session.pop('ontask_workflow_name', None) return render( request, 'dataops/sql_connections_admin.html', { 'table': SQLConnectionTableAdmin(SQLConnection.objects.all().values( 'id', 'name', 'description_txt'), orderable=False) })
def create(self, validated_data, **kwargs): """Create the new object.""" attributes = validated_data.get('attributes', {}) if not isinstance(attributes, dict): raise APIException( _('Attributes must be a dictionary of (string, string) pairs.') ) if any(not isinstance(key, str) or not isinstance(aval, str) for key, aval in list(attributes.items())): raise APIException(_('Attributes must be a dictionary (str, str)')) workflow_obj = None try: workflow_obj = Workflow( user=self.context['request'].user, name=validated_data['name'], description_text=validated_data.get('description_text', ''), nrows=0, ncols=0, attributes=attributes, ) workflow_obj.save() except Exception: if workflow_obj and workflow_obj.id: workflow_obj.delete() raise APIException(_('Workflow could not be created.')) return workflow_obj
def do_workflow_update_lusers(workflow: Workflow, log_item: Log): """Recalculate the field lusers. Recalculate the elements in the field lusers of the workflow based on the fields luser_email_column and luser_email_column_MD5 :param workflow: Workflow to update :param log_item: Log where to leave the status of the operation :return: Changes in the lusers ManyToMany relationships """ # Get the column content emails = get_rows(workflow.get_data_frame_table_name(), column_names=[workflow.luser_email_column.name]) luser_list = [] created = 0 for row in emails: uemail = row[workflow.luser_email_column.name] luser = get_user_model().objects.filter(email=uemail).first() if not luser: # Create user if settings.DEBUG: # Define users with the same password in development password = '******' # NOQA else: password = get_random_string(length=RANDOM_PWD_LENGTH) luser = get_user_model().objects.create_user( email=uemail, password=password, ) created += 1 luser_list.append(luser) # Assign result workflow.lusers.set(luser_list) # Report status log_item.payload['total_users'] = emails.rowcount log_item.payload['new_users'] = created log_item.payload['status'] = ugettext( 'Learner emails successfully updated.', ) log_item.save()
def check_key_columns(workflow: Workflow): """Check that key columns maintain their property. Function used to verify that after changes in the DB the key columns maintain their property. :param workflow: Object to use for the verification. :return: Nothing. Raise exception if key column lost the property. """ col_name = next( (col.name for col in workflow.columns.filter(is_key=True) if not is_column_unique(workflow.get_data_frame_table_name(), col.name)), None) if col_name: raise Exception( _('The new data does not preserve the key ' + 'property of column "{0}"'.format(col_name)))
def edit_action_in( request: HttpRequest, workflow: Workflow, action: Action, ) -> HttpResponse: """Edit an action in. :param request: Request object :param workflow: workflow :param action: Action :return: HTTP response """ # All tuples (action, column, condition) to consider tuples = action.column_condition_pair.all() # Columns all_columns = workflow.columns # Conditions filter_condition = action.get_filter() all_conditions = action.conditions.filter(is_filter=False) # Create the context info. context = { 'action': action, # Workflow elements 'total_rows': workflow.nrows, 'query_builder_ops': workflow.get_query_builder_ops_as_str(), 'has_data': workflow.has_table(), 'selected_rows': filter_condition.n_rows_selected if filter_condition else -1, 'all_false_conditions': any( cond.n_rows_selected == 0 for cond in all_conditions ), # Column elements 'key_columns': all_columns.filter(is_key=True), 'stat_columns': all_columns.filter(is_key=False), 'key_selected': tuples.filter(column__is_key=True).first(), 'has_no_key': tuples.filter(column__is_key=False).exists(), 'any_empty_description': tuples.filter( column__description_text='', column__is_key=False, ).exists(), 'columns_to_insert': all_columns.exclude( column_condition_pair__action=action, ).exclude( is_key=True, ).distinct().order_by('position'), 'column_selected_table': ColumnSelectedTable( tuples.filter(column__is_key=False).values( 'id', 'column__id', 'column__name', 'column__description_text', 'condition__name', ), orderable=False, extra_columns=[( 'operations', OperationsColumn( verbose_name='', template_file=ColumnSelectedTable.ops_template, template_context=lambda record: { 'id': record['column__id'], 'aid': action.id}), )], condition_list=all_conditions, ), # Conditions 'filter_condition': filter_condition, 'conditions': all_conditions, 'vis_scripts': PlotlyHandler.get_engine_scripts(), 'other_conditions': Condition.objects.filter( action__workflow=workflow, is_filter=False, ).exclude(action=action), } return render(request, 'action/edit_in.html', context)
def get_actions(self, datalab): actions = Workflow.objects(datalab=datalab.id) serializer = ActionSerializer(actions, many=True) return serializer.data
def save_attribute_form( request: HttpRequest, workflow: Workflow, template: str, form: forms.Form, attr_idx: int ) -> JsonResponse: """Process the AJAX request to create or update an attribute. :param request: Request object received :param workflow: current workflow being manipulated :param template: Template to render in the response :param form: Form used to ask for data :param attr_idx: Index of the attribute being manipulated :return: AJAX reponse """ if request.method == 'POST' and form.is_valid(): # Correct form submitted if not form.has_changed(): return JsonResponse({'html_redirect': None}) # proceed with updating the attributes. wf_attributes = workflow.attributes # If key_idx is not -1, this means we are editing an existing pair if attr_idx != -1: key = sorted(wf_attributes.keys())[attr_idx] wf_attributes.pop(key) # Rename the appearances of the variable in all actions for action_item in workflow.actions.all(): action_item.rename_variable(key, form.cleaned_data['key']) # Update value wf_attributes[form.cleaned_data['key']] = form.cleaned_data[ 'attr_value'] workflow.attributes = wf_attributes workflow.save() # Log the event Log.objects.register( request.user, Log.WORKFLOW_ATTRIBUTE_CREATE, workflow, { 'id': workflow.id, 'name': workflow.name, 'attr_key': form.cleaned_data['key'], 'attr_val': form.cleaned_data['attr_value']}) return JsonResponse({'html_redirect': ''}) return JsonResponse({ 'html_form': render_to_string( template, {'form': form, 'id': attr_idx}, request=request), })
def access_workflow( request, wid: Optional[int], select_related: Optional[Union[str, List]] = None, prefetch_related: Optional[Union[str, List]] = None, ) -> Optional[Workflow]: """Verify that the workflow stored in the request can be accessed. :param request: HTTP request object :param wid: ID of the workflow that is being requested :param select_related: Field to add as select_related query filter :param prefetch_related: Field to add as prefetch_related query filter :return: Workflow object or raise exception with message """ # Lock the workflow object while deciding if it is accessible or not to # avoid race conditions. sid = request.session.get('ontask_workflow_id') if wid is None and sid is None: # No key was given and none was found in the session (anomaly) return None if wid is None: # No WID provided, but the session contains one, carry on # with this one wid = sid elif sid != wid: Workflow.unlock_workflow_by_id(sid) with cache.lock('ONTASK_WORKFLOW_{0}'.format(wid)): # Step 1: Get the workflow that is being accessed workflow = Workflow.objects.filter(id=wid).filter( Q(user=request.user) | Q(shared__id=request.user.id), ) if not workflow: return None # Apply select and prefetch if given if select_related: if isinstance(select_related, list): workflow = workflow.select_related(*select_related) else: workflow = workflow.select_related(select_related) if prefetch_related: if isinstance(prefetch_related, list): workflow = workflow.prefetch_related(*prefetch_related) else: workflow = workflow.prefetch_related(prefetch_related) # Now get the unique element from the query set workflow = workflow.first() # Step 2: If the workflow is locked by this user session, return # correct result (the session_key may be None if using the API) if request.session.session_key == workflow.session_key: # Update nrows. Asynch execution of plugin may have modified it store_workflow_nrows_in_session(request, workflow) return workflow # Step 3: If the workflow is unlocked, LOCK and return if not workflow.session_key: # Workflow is unlocked. Proceed to lock return wf_lock_and_update(request, workflow, create_session=True) # Step 4: The workflow is locked by a session different from this one. # See if the session locking it is still valid session = Session.objects.filter( session_key=workflow.session_key, ).first() if not session: # The session stored as locking the # workflow is no longer in the session table, so the user can # access the workflow return wf_lock_and_update(request, workflow, create_session=True) # Get the owner of the session locking the workflow user_id = session.get_decoded().get('_auth_user_id') if not user_id: # Session has no user_id, so proceed to lock the workflow return wf_lock_and_update(request, workflow) owner = get_user_model().objects.get(id=user_id) # Step 5: The workflow is locked by a session that is valid. See # if the session locking happens to be from the same user (a # previous session that has not been properly closed, or an API # call from the same user) if owner == request.user: return wf_lock_and_update(request, workflow) # Step 6: The workflow is locked by an existing session. See if the # session is valid if session.expire_date >= timezone.now(): raise OnTaskException( _('The workflow is being modified by user {0}').format( owner.email), ) # The workflow is locked by a session that has expired. Take the # workflow and lock it with the current session. return wf_lock_and_update(request, workflow)
def _do_clone_workflow(workflow: Workflow) -> Workflow: """Clone the workflow. :param workflow: source workflow :return: Clone object """ new_workflow = Workflow( user=workflow.user, name=create_new_name( workflow.name, Workflow.objects.filter( Q(user=workflow.user) | Q(shared=workflow.user)), ), description_text=workflow.description_text, nrows=workflow.nrows, ncols=workflow.ncols, attributes=copy.deepcopy(workflow.attributes), query_builder_ops=copy.deepcopy(workflow.query_builder_ops), luser_email_column_md5=workflow.luser_email_column_md5, lusers_is_outdated=workflow.lusers_is_outdated) new_workflow.save() try: new_workflow.shared.set(list(workflow.shared.all())) new_workflow.lusers.set(list(workflow.lusers.all())) # Clone the columns for item_obj in workflow.columns.all(): do_clone_column_only(item_obj, new_workflow=new_workflow) # Update the luser_email_column if needed: if workflow.luser_email_column: new_workflow.luser_email_column = new_workflow.columns.get( name=workflow.luser_email_column.name, ) # Clone the DB table clone_table(workflow.get_data_frame_table_name(), new_workflow.get_data_frame_table_name()) # Clone actions for item_obj in workflow.actions.all(): do_clone_action(item_obj, new_workflow) for item_obj in workflow.views.all(): do_clone_view(item_obj, new_workflow) # Done! new_workflow.save() except Exception as exc: new_workflow.delete() raise exc return new_workflow
def as_workflow(self): return Workflow(self.workflow)
def workflow_delete_column( workflow: Workflow, column: Column, cond_to_delete: Optional[List[Condition]] = None, ): """Remove column from workflow. Given a workflow and a column, removes it from the workflow (and the corresponding data frame :param workflow: Workflow object :param column: Column object to delete :param cond_to_delete: List of conditions to delete after removing the column :return: Nothing. Effect reflected in the database """ # Drop the column from the DB table storing the data frame df_drop_column(workflow.get_data_frame_table_name(), column.name) # Reposition the columns above the one being deleted workflow.reposition_columns(column.position, workflow.ncols + 1) # Delete the column column.delete() # Update the information in the workflow workflow.ncols = workflow.ncols - 1 workflow.save() if not cond_to_delete: # The conditions to delete are not given, so calculate them # Get the conditions/actions attached to this workflow cond_to_delete = [ cond for cond in Condition.objects.filter(action__workflow=workflow, ) if column in cond.columns.all() ] # If a column disappears, the conditions that contain that variable # are removed actions_without_filters = [] for condition in cond_to_delete: if condition.is_filter: actions_without_filters.append(condition.action) # Formula has the name of the deleted column. Delete it condition.delete() # Traverse the actions for which the filter has been deleted and reassess # all their conditions # TODO: Explore how to do this asynchronously (or lazy) map(lambda act: act.update_n_rows_selected(), actions_without_filters) # If a column disappears, the views that contain only that column need to # disappear as well as they are no longer relevant. for view in workflow.views.all(): if view.columns.count() == 0: view.delete()
def workflow_edit(request, object_id=None, api=False): if object_id: try: workflow_obj = Workflow.objects.get(pk=object_id) except Workflow.DoesNotExist: if api: return JsonResponse({'error': _('Object does not exist')}, status=404) return HttpResponseNotFound() else: workflow_obj = Workflow() if request.method == "GET": action = request.GET.get('action') if action == "dependencies": mode = request.GET.get('mode') if not mode: data = { 'frontends': [ f.to_dict() for f in Frontend.objects.filter( enabled=True, mode__in=('http', 'tcp')) ] } else: data = { 'acls': [ a.to_template() for a in AccessControl.objects.filter(enabled=True) ], 'backends': [ b.to_dict() for b in Backend.objects.filter(enabled=True, mode=mode) ], 'waf_policies': [w.to_template() for w in DefenderPolicy.objects.all()], 'authentications': [a.to_template() for a in BaseRepository.objects.all()], } return JsonResponse({'status': True, 'data': data}) elif action == "get_workflow": return JsonResponse({ 'status': True, 'data': workflow_obj.to_dict(), 'frontends': [f.to_dict() for f in Frontend.objects.filter(enabled=True)], 'backends': [ b.to_dict() for b in Backend.objects.filter( enabled=True, mode=workflow_obj.frontend.mode) ], }) return render(request, "main/workflow_edit.html", {'workflow': workflow_obj}) elif request.method == "POST": return save_workflow(request, workflow_obj, object_id)
def create(self, validated_data, **kwargs): """Create the new workflow.""" wflow_name = self.context.get('name') if not wflow_name: wflow_name = self.validated_data.get('name') if not wflow_name: raise Exception(_('Unexpected empty workflow name.')) if Workflow.objects.filter(name=wflow_name, user=self.context['user']).exists(): raise Exception( _('There is a workflow with this name. ' + 'Please provide a workflow name in the import page.')) # Initial values workflow_obj = None try: workflow_obj = Workflow( user=self.context['user'], name=wflow_name, description_text=validated_data['description_text'], nrows=0, ncols=0, attributes=validated_data['attributes'], query_builder_ops=validated_data.get('query_builder_ops', {}), ) workflow_obj.save() # Create the columns column_data = ColumnSerializer(data=validated_data.get( 'columns', []), many=True, context={'workflow': workflow_obj}) # And save its content if column_data.is_valid(): columns = column_data.save() else: raise Exception(_('Unable to save column information')) # If there is any column with position = 0, recompute (this is to # guarantee backward compatibility. if any(col.position == 0 for col in columns): for idx, col in enumerate(columns): col.position = idx + 1 col.save() # Load the data frame data_frame = validated_data.get('data_frame') if data_frame is not None: # Store the table in the DB store_table( data_frame, workflow_obj.get_data_frame_table_name(), dtype={ col.name: col.data_type for col in workflow_obj.columns.all() }, ) # Reconcile now the information in workflow and columns with # the one loaded workflow_obj.ncols = validated_data['ncols'] workflow_obj.nrows = validated_data['nrows'] workflow_obj.save() # Create the actions pointing to the workflow action_data = ActionSerializer(data=validated_data.get( 'actions', []), many=True, context={ 'workflow': workflow_obj, 'columns': columns }) if action_data.is_valid(): action_data.save() else: raise Exception(_('Unable to save column information')) # Create the views pointing to the workflow view_data = ViewSerializer(data=validated_data.get('views', []), many=True, context={ 'workflow': workflow_obj, 'columns': columns }) if view_data.is_valid(): view_data.save() else: raise Exception(_('Unable to save column information')) except Exception: # Get rid of the objects created if workflow_obj: if workflow_obj.id: workflow_obj.delete() raise return workflow_obj
def edit_action_out( request: HttpRequest, workflow: Workflow, action: Action, ) -> HttpResponse: """Edit action out. :param request: Request object :param workflow: The workflow with the action :param action: Action :return: HTML response """ # Create the form form = EditActionOutForm(request.POST or None, instance=action) form_filter = FilterForm( request.POST or None, instance=action.get_filter(), action=action ) # Processing the request after receiving the text from the editor if request.method == 'POST' and form.is_valid() and form_filter.is_valid(): # Get content text_content = form.cleaned_data.get('text_content') # Render the content as a template and catch potential problems. if text_renders_correctly(text_content, action, form): # Log the event Log.objects.register( request.user, Log.ACTION_UPDATE, action.workflow, {'id': action.id, 'name': action.name, 'workflow_id': workflow.id, 'workflow_name': workflow.name, 'content': text_content}) # Text is good. Update the content of the action action.set_text_content(text_content) if action.action_type == Action.personalized_json: # Update the target_url field action.target_url = form.cleaned_data['target_url'] action.save() if request.POST['Submit'] == 'Submit': return redirect(request.get_full_path()) return redirect('action:index') # This is a GET request or a faulty POST request # Get the filter or None filter_condition = action.get_filter() # Context to render the form context = { 'filter_condition': filter_condition, 'action': action, 'load_summernote': action.action_type == Action.personalized_text, 'conditions': action.conditions.filter(is_filter=False), 'other_conditions': Condition.objects.filter( action__workflow=workflow, is_filter=False, ).exclude(action=action), 'query_builder_ops': workflow.get_query_builder_ops_as_str(), 'attribute_names': [ attr for attr in list(workflow.attributes.keys()) ], 'columns': workflow.columns.all(), 'stat_columns': workflow.columns.filter(is_key=False), 'selected_rows': filter_condition.n_rows_selected if filter_condition else -1, 'has_data': action.workflow.has_table(), 'all_false_conditions': any( cond.n_rows_selected == 0 for cond in action.conditions.all()), 'rows_all_false': action.get_row_all_false_count(), 'total_rows': workflow.nrows, 'form': form, 'form_filter': form_filter, 'vis_scripts': PlotlyHandler.get_engine_scripts(), } # Return the same form in the same page return render(request, 'action/edit_out.html', context=context)
def post(self, request, object_id=None, action=None): try: if not action: # return workflow_edit(request, None, api=True) pass enabled = request.POST.get('enabled') is not False defender_policy = False fqdn = "" public_dir = "/" try: frontend = Frontend.objects.get(pk=request.POST['frontend']) if frontend.mode == "http": try: fqdn = request.POST['fqdn'] if not validators.domain(fqdn): return JsonResponse({ 'error': _('This FQDN is not valid') }) public_dir = request.POST['public_dir'] if public_dir and len(public_dir): if public_dir[0] != '/': public_dir = '/' + public_dir if public_dir[-1] != '/': public_dir += '/' except KeyError: return JsonResponse({ 'error': _('For a HTTP Frontend, you must define a FQDN & a public_dir') }) except Frontend.DoesNotExist: return JsonResponse({ 'error': _('frontend with id {} does not exist'.format(request.POST['frontend'])) }, status=401) except KeyError: return JsonResponse({ 'error': _('You must define a frontend for a workflow') }, status=401) try: backend = Backend.objects.get(pk=request.POST['backend']) if frontend.mode != backend.mode: return JsonResponse({ 'error': _('Frontend and Backend must be in the same mode.') }) except Backend.DoesNotExist: return JsonResponse({ 'error': _('Backend with id {} does not exist'.format(request.POST['backend'])) }, status=401) except KeyError: return JsonResponse({ 'error': _('You must define a backend for a workflow') }, status=401) if request.POST.get('defender_policy'): try: defender_policy = DefenderPolicy.objects.get(pk=request.POST['defender_policy']) except DefenderPolicy.DoesNotExist: return JsonResponse({ 'error': _('Defender Policy with id {} does not exist'.format(request.POST['defender_policy'])) }, status=401) try: if object_id: workflow = Workflow.objects.get(pk=object_id) else: workflow = Workflow() workflow.enabled = enabled workflow.name = request.POST['name'] workflow.fqdn = fqdn workflow.public_dir = public_dir workflow.frontend = frontend workflow.backend = backend workflow.save() workflow_acls = [] if defender_policy: workflow.defender_policy = defender_policy workflow.workflowacl_set.all().delete() for i, tmp_acl in enumerate(json.loads(request.POST.get('acl_frontend', "[]"))): status, acl = format_acl_from_api(tmp_acl, i, before_policy=True) if not status: return acl acl.workflow = workflow workflow_acls.append(acl) acl.save() for i, tmp_acl in enumerate(json.loads(request.POST.get('acl_backend', "[]"))): status, acl = format_acl_from_api(tmp_acl, i, before_policy=False) if not status: return acl acl.workflow = workflow workflow_acls.append(acl) acl.save() workflow.workflow_json = generate_workflow(workflow) workflow.save() nodes = workflow.frontend.reload_conf() workflow.backend.reload_conf() if workflow.defender_policy: logger.info("Need to reload the Defender Policy SPOE configuration") Cluster.api_request( "darwin.defender_policy.policy.write_defender_backend_conf", workflow.defender_policy.pk ) Cluster.api_request( "darwin.defender_policy.policy.write_defender_spoe_conf", workflow.defender_policy.pk ) # Reload HAProxy on concerned nodes for node in nodes: api_res = node.api_request("services.haproxy.haproxy.restart_service") if not api_res.get('status'): logger.error("Workflow::edit: API error while trying to " "restart HAProxy service : {}".format(api_res.get('message'))) for workflow_acl in workflow.workflowacl_set.all(): workflow_acl.delete() try: workflow.delete() except Exception: pass return JsonResponse({ 'error': api_res.get('message') }, status=500) return JsonResponse({ 'message': _('Workflow saved') }) except KeyError: return JsonResponse({ 'error': _('Partial data') }, status=401) if action and not object_id: return JsonResponse({ 'error': _('You must specify an ID') }, status=401) if action not in list(COMMAND_LIST.keys()): return JsonResponse({ 'error': _('Action not allowed') }, status=403) return COMMAND_LIST[action](request, object_id, api=True) except Exception as e: logger.critical(e, exc_info=1) if settings.DEV_MODE: error = str(e) else: error = _("An error has occurred") return JsonResponse({ 'error': error }, status=500)