Пример #1
0
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'))
Пример #2
0
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()
Пример #3
0
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)
Пример #4
0
 def setUp(self):
     self.setup_test()
     self.workflow = Workflow(
         {"root": [{
             "key": "MY_GROUP",
             "children": []
         }]})
Пример #5
0
 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)
Пример #6
0
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
Пример #7
0
    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
Пример #8
0
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)
        })
Пример #9
0
    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
Пример #10
0
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()
Пример #11
0
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)))
Пример #12
0
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)
Пример #13
0
 def get_actions(self, datalab):
     actions = Workflow.objects(datalab=datalab.id)
     serializer = ActionSerializer(actions, many=True)
     return serializer.data
Пример #14
0
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),
    })
Пример #15
0
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)
Пример #16
0
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
Пример #17
0
 def as_workflow(self):
     return Workflow(self.workflow)
Пример #18
0
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()
Пример #19
0
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)
Пример #20
0
    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
Пример #21
0
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)
Пример #22
0
    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)