Beispiel #1
0
    def execute_operation(
        self,
        user,
        workflow: Optional[models.Workflow] = None,
        action: Optional[models.Action] = None,
        payload: Optional[Dict] = None,
        log_item: Optional[models.Log] = None,
    ):
        """Send single json object to target URL.

        Sends a single json object to the URL in the action

        :param user: User object that executed the action
        :param workflow: Workflow object (if relevant)
        :param action: Action from where to take the messages
        :param payload: Object with the additional parameters
        :param log_item: Log object to store results
        :return: Empty list (there are no column values for multiple sends)
        """
        if log_item is None:
            action.log(user, self.log_event, action=action.id, **payload)

        action_text = evaluate_row_action_out(
            action, get_action_evaluation_context(action, {}))

        _send_and_log_json(
            user, action, json.loads(action_text), {
                'content-type':
                'application/x-www-form-urlencoded; ' + 'charset=UTF-8',
                'Authorization': 'Bearer {0}'.format(payload['token']),
            })

        action.last_executed_log = log_item
        action.save(update_fields=['last_executed_log'])
Beispiel #2
0
def preview_response(
    request: HttpRequest,
    pk: int,
    idx: int,
    workflow: Optional[Workflow] = None,
    action: Optional[Action] = None,
) -> JsonResponse:
    """Preview content of action.

    HTML request and the primary key of an action to preview one of its
    instances. The request must provide and additional parameter idx to
    denote which instance to show.

    :param request: HTML request object

    :param pk: Primary key of the an action for which to do the preview

    :param idx: Index of the reponse to preview

    :param action: Might have been fetched already

    :return: JsonResponse
    """
    # 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()

    # Initial context to render the response page.
    context = {
        'action': action,
        'index': idx,
    }

    if (
        action.action_type == Action.SEND_LIST
        or action.action_type == Action.SEND_LIST_JSON
    ):
        # Obtain the evaluation context (no condition evaluation)
        action_final_text = evaluate_row_action_out(
            action,
            get_action_evaluation_context(action, {}))
        context['action_content'] = action_final_text
        if action.action_type == Action.SEND_LIST_JSON:
            incorrect_json = not _check_json_is_correct(action_final_text)
            context['incorrect_json'] = incorrect_json
    else:
        _create_row_preview_response(
            action,
            idx,
            context,
            request.GET.get('subject_content'))

    return JsonResponse({
        'html_form': render_to_string(
            'action/includes/partial_preview.html',
            context,
            request=request)})
Beispiel #3
0
def serve_action_out(
    user,
    action: Action,
    user_attribute_name: str,
):
    """Serve request for an action out.

    Function that given a user and an Action Out
    searches for the appropriate data in the table with the given
    attribute name equal to the user email and returns the HTTP response.
    :param user: User object making the request
    :param action: Action to execute (action out)
    :param user_attribute_name: Column to check for email
    :return:
    """
    # For the response
    payload = {'action': action.name, 'action_id': action.id}

    # User_instance has the record used for verification
    row_values = get_row_values(action, (user_attribute_name, user.email))

    # Get the dictionary containing column names, attributes and condition
    # valuations:
    context = get_action_evaluation_context(action, row_values)
    if context is None:
        payload['error'] = (
            _('Error when evaluating conditions for user {0}').format(
                user.email, ))
        # Log the event
        Log.objects.register(user,
                             Log.ACTION_SERVED_EXECUTE,
                             workflow=action.workflow,
                             payload=payload)
        return HttpResponse(
            render_to_string('action/action_unavailable.html', {}))

    # Evaluate the action content.
    action_content = evaluate_row_action_out(action, context)

    # If the action content is empty, forget about it
    response = action_content
    if action_content is None:
        response = render_to_string('action/action_unavailable.html', {})
        payload['error'] = _('Action not enabled for user {0}').format(
            user.email, )

    # Log the event
    Log.objects.register(user,
                         Log.ACTION_SERVED_EXECUTE,
                         workflow=action.workflow,
                         payload=payload)

    # Respond the whole thing
    return HttpResponse(response)
Beispiel #4
0
def create_list_preview_context(
    action: models.Action,
    context: Dict,
):
    """Create the elements to render a single row preview.

    :param action: Action being previewed.
    :param context: Dictionary to render the page
    :return: context is modified to include the appropriate items
    """
    # Obtain the evaluation context (no condition evaluation)
    action_final_text = evaluate_row_action_out(
        action, get_action_evaluation_context(action, {}))
    context['action_content'] = action_final_text
    if action.action_type == models.Action.JSON_REPORT:
        incorrect_json = not _check_json_is_correct(action_final_text)
        context['incorrect_json'] = incorrect_json
Beispiel #5
0
def get_survey_context(
    request: http.HttpRequest,
    is_manager: bool,
    action: models.Action,
    user_attribute_name: str,
) -> Dict:
    """Get the context to render a survey page.

    :param request: Request received
    :param is_manager: User is manager
    :param action: Action object being executed
    :param user_attribute_name: Name of the column to use for username
    :return: Dictionary with the context
    """
    # Get the attribute value depending if the user is managing the workflow
    # User is instructor, and either owns the workflow or is allowed to access
    # it as shared
    user_attribute_value = None
    if is_manager:
        user_attribute_value = request.GET.get('uatv')
    if not user_attribute_value:
        user_attribute_value = request.user.email

    # Get the dictionary containing column names, attributes and condition
    # valuations:
    context = get_action_evaluation_context(
        action,
        get_row_values(
            action,
            (user_attribute_name, user_attribute_value),
        ),
    )

    if not context:
        # If the data has not been found, flag
        if not is_manager:
            raise OnTaskActionSurveyDataNotFound()

        raise OnTaskActionSurveyNoTableData(
            message=_('Data not found in the table'))

    return context
def _create_row_preview_response(
    action: Action,
    idx: int,
    page_context: Dict,
    prelude: str = None,
):
    """Create the elements to render a sigle row preview.

    :param action: Action being previewed.
    :param idx:
    :param page_context:
    :return: page_context is modified to include the appropriate items
    """

    # Get the total number of items
    filter_obj = action.get_filter()
    if filter_obj:
        n_items = filter_obj.n_rows_selected
    else:
        n_items = action.workflow.nrows

    # Set the correct values to the indeces
    prv, idx, nxt = _get_navigation_index(idx, n_items)

    row_values = get_row_values(action, idx)

    # Obtain the dictionary with the condition evaluation
    condition_evaluation = action_condition_evaluation(action, row_values)
    # Get the dictionary containing column names, attributes and condition
    # valuations:
    eval_context = get_action_evaluation_context(action, row_values,
                                                 condition_evaluation)

    all_false = False
    if action.conditions.filter(is_filter=False).count():
        # If there are conditions, check if they are all false
        all_false = all(not bool_val
                        for __, bool_val in condition_evaluation.items())

    # Evaluate the action content.
    show_values = ''
    incorrect_json = False
    if action.is_out:
        action_content = evaluate_row_action_out(action, eval_context)
        if action.action_type == Action.personalized_json:
            incorrect_json = not _check_json_is_correct(action_content)
    else:
        action_content = evaluate_row_action_in(action, eval_context)
    if action_content is None:
        action_content = _(
            'Error while retrieving content for student {0}', ).format(idx)
    else:
        # Get the conditions used in the action content
        act_cond = action.get_used_conditions()
        # Get the variables/columns from the conditions
        act_vars = set().union(
            *[
                cond.columns.all()
                for cond in action.conditions.filter(name__in=act_cond)
            ], )
        # Sort the variables/columns  by position and get the name
        show_values = ', '.join([
            '{0} = {1}'.format(col.name, row_values[col.name])
            for col in act_vars
        ], )

    uses_plain_text = (action.action_type == Action.personalized_canvas_email
                       or action.action_type == Action.personalized_json)
    if uses_plain_text:
        action_content = escape(action_content)

    if prelude:
        prelude = evaluate_row_action_out(action, eval_context, prelude)

    # Update the context
    page_context.update({
        'n_items': n_items,
        'nxt': nxt,
        'prv': prv,
        'incorrect_json': incorrect_json,
        'show_values': show_values,
        'all_false': all_false,
        'prelude': prelude,
        'action_content': action_content,
        'show_navigation': True
    })

    return
Beispiel #7
0
def serve_survey_row(
    request: HttpRequest,
    action: Action,
    user_attribute_name: str,
) -> HttpResponse:
    """Serve a request for action in.

    Function that given a request, and an action IN, it performs the lookup
     and data input of values.

    :param request: HTTP request

    :param action:  Action In

    :param user_attribute_name: The column name used to check for email

    :return:
    """
    # Get the attribute value depending if the user is managing the workflow
    # User is instructor, and either owns the workflow or is allowed to access
    # it as shared
    manager = has_access(request.user, action.workflow)
    user_attribute_value = None
    if manager:
        user_attribute_value = request.GET.get('uatv')
    if not user_attribute_value:
        user_attribute_value = request.user.email

    # Get the dictionary containing column names, attributes and condition
    # valuations:
    context = get_action_evaluation_context(
        action,
        get_row_values(
            action,
            (user_attribute_name, user_attribute_value),
        ),
    )

    if not context:
        # If the data has not been found, flag
        if not manager:
            return ontask_handler404(request, None)

        messages.error(request, _('Data not found in the table'))
        return redirect(reverse('action:run', kwargs={'pk': action.id}))

    # Get the active columns attached to the action
    colcon_items = extract_survey_questions(action, request.user)

    # Bind the form with the existing data
    form = EnterActionIn(
        request.POST or None,
        tuples=colcon_items,
        context=context,
        values=[context[colcon.column.name] for colcon in colcon_items],
        show_key=manager)

    keep_processing = (request.method == 'POST' and form.is_valid()
                       and not request.POST.get('lti_version'))
    if keep_processing:
        # Update the content in the DB
        row_keys, row_values = survey_update_row_values(
            action, colcon_items, manager, form.cleaned_data, 'email',
            request.user.email, context)

        # Log the event and update its content in the action
        log_item = action.log(request.user,
                              Log.ACTION_SURVEY_INPUT,
                              new_values=json.dumps(
                                  dict(zip(row_keys, row_values))))

        # Modify the time of execution for the action
        action.last_executed_log = log_item
        action.save()

        # If not instructor, just thank the user!
        if not manager:
            return render(request, 'thanks.html', {})

        # Back to running the action
        return redirect(reverse('action:run', kwargs={'pk': action.id}))

    return render(
        request,
        'action/run_survey_row.html',
        {
            'form':
            form,
            'action':
            action,
            'cancel_url':
            reverse(
                'action:run',
                kwargs={'pk': action.id},
            ) if manager else None,
        },
    )
Beispiel #8
0
def create_row_preview_context(
    action: models.Action,
    idx: int,
    context: Dict,
    prelude: Optional[str] = None,
):
    """Create the elements to render a single row preview.

    :param action: Action being previewed.
    :param idx:
    :param context:
    :param prelude: Optional additional text to include in the preview.
    :return: context is modified to include the appropriate items
    """
    # Get the total number of items
    filter_obj = action.get_filter()
    if filter_obj:
        n_items = filter_obj.n_rows_selected
    else:
        n_items = action.workflow.nrows

    # Set the correct values to the indeces
    prv, idx, nxt = _get_navigation_index(idx, n_items)

    row_values = get_row_values(action, idx)

    # Obtain the dictionary with the condition evaluation
    condition_evaluation = action_condition_evaluation(action, row_values)
    # Get the dictionary containing column names, attributes and condition
    # valuations:
    eval_context = get_action_evaluation_context(action, row_values,
                                                 condition_evaluation)

    all_false = False
    if action.conditions.filter(is_filter=False).count():
        # If there are conditions, check if they are all false
        all_false = all(not bool_val
                        for __, bool_val in condition_evaluation.items())

    # Evaluate the action content.
    show_values = ''
    incorrect_json = False
    if action.is_out:
        action_content = evaluate_row_action_out(action, eval_context)
        if action.action_type == models.Action.PERSONALIZED_JSON:
            incorrect_json = not _check_json_is_correct(action_content)
    else:
        action_content = _evaluate_row_action_in(action, eval_context)
    if action_content is None:
        action_content = _(
            'Error while retrieving content (index: {0})', ).format(idx)
    else:
        # Get the conditions used in the action content
        act_cond = action.get_used_conditions()
        # Get the variables/columns from the conditions
        act_vars = set().union(*[
            cond.columns.all()
            for cond in action.conditions.filter(name__in=act_cond)
        ])

        act_vars = act_vars.union(
            {triplet.column
             for triplet in action.column_condition_pair.all()})

        # Sort the variables/columns  by position and get the name
        show_values = ', '.join([
            '"{0}" = {1}'.format(col.name, row_values[col.name])
            for col in act_vars
        ])

    uses_plain_text = (
        action.action_type == models.Action.PERSONALIZED_CANVAS_EMAIL
        or action.action_type == models.Action.PERSONALIZED_JSON)
    if uses_plain_text:
        action_content = escape(action_content)

    if prelude:
        prelude = evaluate_row_action_out(action, eval_context, prelude)

    # Update the context
    context.update({
        'n_items':
        n_items,
        'nxt':
        nxt,
        'prv':
        prv,
        'incorrect_json':
        incorrect_json,
        'show_values':
        show_values,
        'show_conditions':
        ', '.join([
            '"{0}" = {1}'.format(cond_name, str(cond_value))
            for cond_name, cond_value in condition_evaluation.items()
        ]),
        'all_false':
        all_false,
        'prelude':
        prelude,
        'action_content':
        action_content,
        'show_navigation':
        True
    })