Beispiel #1
0
def _create_columns(new_columns, context):
    """Add new_columns just created to the DB in the given context.

    :param new_columns: List of columns that have been already created
    :param context: Dictionary to pass the serializer with extra info
    :return: List of new column objects
    """
    if not new_columns:
        return []

    workflow = context['workflow']

    # There are some new columns that need to be created
    column_data = ColumnSerializer(data=new_columns,
                                   many=True,
                                   context=context)

    # And save its content
    if not column_data.is_valid():
        raise Exception(_('Unable to create column data'))
    new_columns = column_data.save()

    # Add columns to DB
    for col in new_columns:
        sql.add_column_to_db(workflow.get_data_frame_table_name(), col.name,
                             col.data_type)

        # Update the column position and count in the workflow
        workflow.ncols = workflow.ncols + 1
        col.position = workflow.ncols
        col.save(update_fields=['position'])

    workflow.save(update_fields=['ncols'])

    return new_columns
Beispiel #2
0
def clone_column(user, column: models.Column) -> models.Column:
    """Create a clone of a column.

    :param user: User executing operation
    :param column: Object to clone
    :return: Cloned object (DF has an additional column as well
    """
    workflow = column.workflow

    new_column = do_clone_column_only(column,
                                      new_name=create_new_name(
                                          column.name, workflow.columns))

    # Update the number of columns in the workflow
    workflow.ncols += 1
    workflow.save()
    workflow.refresh_from_db()

    # Reposition the new column at the end
    new_column.position = workflow.ncols
    new_column.save()

    # Create the column in the database
    sql.add_column_to_db(workflow.get_data_frame_table_name(), new_column.name,
                         new_column.data_type)

    sql.copy_column_in_db(workflow.get_data_frame_table_name(), column.name,
                          new_column.name)

    new_column.log(user, models.Log.COLUMN_CLONE)

    return new_column
Beispiel #3
0
def clone_wf_column(column: Column) -> Column:
    """Create a clone of a column.

    :param column: Object to clone

    :return: Cloned object (DF has an additional column as well
    """
    workflow = column.workflow

    new_column = do_clone_column_only(column,
                                      new_name=create_new_name(
                                          column.name, workflow.columns))

    # Update the number of columns in the workflow
    workflow.ncols += 1
    workflow.save()
    workflow.refresh_from_db()

    # Reposition the new column at the end
    new_column.position = workflow.ncols
    new_column.save()

    # Create the column in the database
    add_column_to_db(workflow.get_data_frame_table_name(), new_column.name,
                     new_column.data_type)

    copy_column_in_db(workflow.get_data_frame_table_name(), column.name,
                      new_column.name)

    return new_column
Beispiel #4
0
def add_column_to_workflow(
    user,
    workflow: models.Workflow,
    column: models.Column,
    column_initial_value: Any,
    action_column_event: Optional[str] = None,
    action: Optional[models.Action] = None,
):
    """Add a new column to the workflow.

    :param user: User executing the operation
    :param workflow: Used workflow
    :param column: Column to insert
    :param column_initial_value: Initial value for the column
    :param action_column_event: Event to record if the action/column needs to
    be stored
    :param action: If the column is a question, this is the action in which it
    is being used.
    :return: Nothing. Column added to Wflow and DB
    """
    # Catch the special case of integer type and no initial value. Pandas
    # encodes it as NaN but a cycle through the database transforms it into
    # a string. To avoid this case, integer + empty value => double
    if column.data_type == 'integer' and column_initial_value is None:
        column.data_type = 'double'

    # Fill in the remaining fields in the column
    column.workflow = workflow
    column.is_key = False

    # Update the positions of the appropriate columns
    workflow.reposition_columns(workflow.ncols + 1, column.position)

    # Save column, refresh workflow, and increase number of columns
    column.save()
    workflow.refresh_from_db()
    workflow.ncols += 1
    workflow.set_query_builder_ops()
    workflow.save()

    # Add the new column to the DB
    try:
        sql.add_column_to_db(
            workflow.get_data_frame_table_name(),
            column.name,
            column.data_type,
            initial=column_initial_value)
    except Exception as exc:
        raise services.OnTaskWorkflowAddColumn(
            message=_('Unable to add element: {0}').format(str(exc)),
            to_delete=[column])

    if action_column_event:
        acc, __ = models.ActionColumnConditionTuple.objects.get_or_create(
            action=action,
            column=column,
            condition=None)
        acc.log(user, action_column_event)
    column.log(user, models.Log.COLUMN_ADD)
Beispiel #5
0
def _create_track_column(action: models.Action) -> str:
    """Create an additional column for email tracking.

    :param action: Action to consider
    :return: column name
    """
    # Make sure the column name does not collide with an existing one
    idx = 0  # Suffix to rename
    cnames = [col.name for col in action.workflow.columns.all()]
    while True:
        idx += 1
        track_col_name = 'EmailRead_{0}'.format(idx)
        if track_col_name not in cnames:
            break

    # Add the column if needed (before the mass email to avoid overload
    # Create the new column and store
    column = models.Column(
        name=track_col_name,
        description_text='Emails sent with action {0} on {1}'.format(
            action.name,
            simplify_datetime_str(
                datetime.datetime.now(pytz.timezone(settings.TIME_ZONE))),
        ),
        workflow=action.workflow,
        data_type='integer',
        is_key=False,
        position=action.workflow.ncols + 1,
    )
    column.save()

    # Increase the number of columns in the workflow
    action.workflow.ncols += 1
    action.workflow.save(update_fields=['ncols'])

    # Add the column to the DB table
    sql.add_column_to_db(action.workflow.get_data_frame_table_name(),
                         track_col_name, 'integer', 0)

    return track_col_name
Beispiel #6
0
def column_add(
    request: HttpRequest,
    pk: Optional[int] = None,
    workflow: Optional[Workflow] = None,
) -> JsonResponse:
    """Add column.

    :param request: Http Request

    :param pk: Action ID where to add the question

    :return: JSON response
    """
    # Detect if this operation is to add a new column or a new question (in
    # the edit in page)
    is_question = pk is not None

    if workflow.nrows == 0:
        if is_question:
            messages.error(
                request,
                _('Cannot add question to a workflow without data'),
            )
        else:
            messages.error(
                request,
                _('Cannot add column to a workflow without data'),
            )
        return JsonResponse({'html_redirect': ''})

    action = None
    action_id = None
    if is_question:
        # Get the action and the columns
        action = workflow.actions.filter(pk=pk).first()
        action_id = action.id
        if not action:
            messages.error(
                request,
                _('Cannot find action to add question.'),
            )
            return JsonResponse({'html_redirect': reverse('action:index')})

    # Form to read/process data
    if is_question:
        form = QuestionAddForm(request.POST or None, workflow=workflow)
    else:
        form = ColumnAddForm(request.POST or None, workflow=workflow)

    if request.method == 'POST' and form.is_valid():

        # Processing now a valid POST request
        # Access the updated information
        column_initial_value = form.initial_valid_value

        # Save the column object attached to the form
        column = form.save(commit=False)

        # Catch the special case of integer type and no initial value. Pandas
        # encodes it as NaN but a cycle through the database transforms it into
        # a string. To avoid this case, integer + empty value => double
        if column.data_type == 'integer' and column_initial_value is None:
            column.data_type = 'double'

        # Fill in the remaining fields in the column
        column.workflow = workflow
        column.is_key = False

        # Update the positions of the appropriate columns
        workflow.reposition_columns(workflow.ncols + 1, column.position)

        # Save column, refresh workflow, and increase number of columns
        column.save()
        form.save_m2m()
        workflow.refresh_from_db()
        workflow.ncols += 1
        workflow.set_query_builder_ops()
        workflow.save()

        # Add the new column to the DB
        try:
            add_column_to_db(workflow.get_data_frame_table_name(),
                             column.name,
                             column.data_type,
                             initial=column_initial_value)
        except Exception as exc:
            messages.error(request,
                           _('Unable to add column: {0}').format(str(exc)))
            return JsonResponse({'html_redirect': ''})

        # If the column is a question, add it to the action
        if is_question:
            ActionColumnConditionTuple.objects.get_or_create(action=action,
                                                             column=column,
                                                             condition=None)

        # Log the event
        if is_question:
            event_type = Log.QUESTION_ADD
        else:
            event_type = Log.COLUMN_ADD
        Log.objects.register(
            request.user, event_type, workflow, {
                'id': workflow.id,
                'name': workflow.name,
                'column_name': column.name,
                'column_type': column.data_type
            })

        return JsonResponse({'html_redirect': ''})

    if is_question:
        template = 'workflow/includes/partial_question_addedit.html'
    else:
        template = 'workflow/includes/partial_column_addedit.html'

    return JsonResponse({
        'html_form':
        render_to_string(template, {
            'form': form,
            'is_question': is_question,
            'action_id': action_id,
            'add': True
        },
                         request=request),
    })
Beispiel #7
0
def criterion_create(
    request: HttpRequest,
    pk: int,
    workflow: Optional[Workflow] = None,
    action: Optional[Workflow] = None,
) -> JsonResponse:
    """Add a new criteria to an action.

    If it is the first criteria, the form simply asks for a question with a
    non-empty category field.

    If it is not the first criteria, then the criteria are fixed by the
    previous elements in the rubric.

    :param request: Http Request

    :param pk: Action ID where to add the question

    :return: JSON response
    """
    if action.action_type != Action.RUBRIC_TEXT:
        messages.error(
            request,
            _('Operation only valid or Rubric actions')
        )
        return JsonResponse({'html_redirect': ''})

    if action.workflow.nrows == 0:
        messages.error(
            request,
            _('Cannot add criteria to a workflow without data'),
        )
        return JsonResponse({'html_redirect': ''})

    # If the request has the 'action_content', update the action
    action_content = request.POST.get('action_content')
    if action_content:
        action.set_text_content(action_content)
        action.save()

    # Form to read/process data
    form = CriterionForm(
        request.POST or None,
        other_criterion=ActionColumnConditionTuple.objects.filter(
            action=action).first(),
        workflow=action.workflow)

    if request.method == 'POST' and form.is_valid():
        # Processing now a valid POST request
        # Access the updated information
        column_initial_value = form.initial_valid_value

        # Save the column object attached to the form
        column = form.save(commit=False)

        # Catch the special case of integer type and no initial value. Pandas
        # encodes it as NaN but a cycle through the database transforms it into
        # a string. To avoid this case, integer + empty value => double
        if column.data_type == 'integer' and column_initial_value is None:
            column.data_type = 'double'

        # Fill in the remaining fields in the column
        column.workflow = workflow
        column.is_key = False

        # Update the positions of the appropriate columns
        workflow.reposition_columns(workflow.ncols + 1, column.position)

        # Save column, refresh workflow, and increase number of columns
        column.save()
        form.save_m2m()
        workflow.refresh_from_db()
        workflow.ncols += 1
        workflow.set_query_builder_ops()
        workflow.save()

        # Add the new column to the DB
        try:
            add_column_to_db(
                workflow.get_data_frame_table_name(),
                column.name,
                column.data_type,
                initial=column_initial_value)
        except Exception as exc:
            messages.error(
                request,
                _('Unable to add criterion: {0}').format(str(exc)))
            return JsonResponse({'html_redirect': ''})

        # Add the criterion to the action
        acc = ActionColumnConditionTuple.objects.get_or_create(
            action=action,
            column=column,
            condition=None)

        # Log the event
        acc.log(request.user, Log.ACTION_RUBRIC_CRITERION_ADD)

        return JsonResponse({'html_redirect': ''})

    return JsonResponse({
        'html_form': render_to_string(
            'workflow/includes/partial_criterion_addedit.html',
            {
                'form': form,
                'action_id': action.id,
                'add': True},
            request=request)})