def vis_html_content(context, column_name): # Get the action action = context.get(action_context_var, None) if not action: raise Exception(_('Action object not found when processing tag')) workflow = action.workflow # Check if the column is correct if not Column.objects.filter(workflow=workflow, name=column_name).exists(): raise Exception(_('Column {0} does not exist').format(column_name)) # Get the visualization number to generate unique IDs viz_number = context[viz_number_context_var] # Create the context for the visualization viz_ctx = { 'style': 'width:400px; height:225px;', 'id': 'viz_tag_{0}'.format(viz_number) } # If there is a column name in the context, insert it as individual value # If the template is simply being saved and rendered to detect syntax # errors, we may not have the data of an individual, so we have to relax # this restriction. ivalue = context.get(tr_item(column_name), None) if ivalue is not None: viz_ctx['individual_value'] = ivalue # Get the condition filter try: cond_filter = Condition.objects.get(action__id=action.id, is_filter=True) except ObjectDoesNotExist: cond_filter = None # Get the data from the data frame df = pandas_db.get_subframe(workflow.id, cond_filter, [column_name]) # Get the visualisation viz = PlotlyColumnHistogram(data=df, context=viz_ctx) prefix = '' if viz_number == 0: prefix = ''.join([ '<script src="{0}"></script>'.format(x) for x in PlotlyColumnHistogram.get_engine_scripts() ]) # Update viz number context[viz_number_context_var] = viz_number + 1 # Return the rendering of the viz marked as safe return mark_safe(prefix + viz.render())
def csvdownload(request, pk=None): """ :param request: HTML request :param pk: If given, the PK of the view to subset the table :return: Return a CSV download of the data in the table """ # Get the appropriate workflow object workflow = get_workflow(request) if not workflow: return redirect('workflow:index') # Check if dataframe is present if not ops.workflow_id_has_table(workflow.id): # Go back to show the workflow detail return redirect(reverse('workflow:detail', kwargs={'pk': workflow.id})) # Get the columns from the view (if given) view = None if pk: try: view = View.objects.filter( Q(workflow__user=request.user) | Q(workflow__shared=request.user) ).distinct().prefetch_related('columns').get(pk=pk) except ObjectDoesNotExist: # Go back to show the workflow detail return redirect(reverse('workflow:detail', kwargs={'pk': workflow.id})) # Fetch the data frame if view: col_names = [x.name for x in view.columns.all()] else: col_names = workflow.get_column_names() data_frame = pandas_db.get_subframe(workflow.id, view, col_names) # Create the response object response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = \ 'attachment; filename="ontask_table.csv"' # Dump the data frame as the content of the response object data_frame.to_csv(path_or_buf=response, sep=str(','), index=False, encoding='utf-8') return response
def evaluate_action(action, extra_string, column_name): """ Given an action object and an optional string: 1) Access the attached workflow 2) Obtain the data from the appropriate data frame 3) Loop over each data row and 3.1) Evaluate the conditions with respect to the values in the row 3.2) Create a context with the result of evaluating the conditions, attributes and column names to values 3.3) Run the template with the context 3.4) Run the optional string argument with the template and the context 3.5) Select the optional column_name 6) Return the resulting objects: List of (HTMLs body, extra string, column name value) or an error message :param action: Action object with pointers to conditions, filter, workflow, etc. :param extra_string: An extra string to process (something like the email subject line) with the same dictionary as the text in the action. :param column_name: Column from where to extract the special value ( typically the email address) and include it in the result. :return: list of lists resulting from the evaluation of the action """ # Step 1: Get the workflow to access the data and prepare data workflow = Workflow.objects.get(pk=action.workflow.id) col_names = workflow.get_column_names() col_idx = -1 if column_name and column_name in col_names: col_idx = col_names.index(column_name) # Step 2: Get the row of data from the DB try: cond_filter = Condition.objects.get(action__id=action.id, is_filter=True) except ObjectDoesNotExist: cond_filter = None # Step 3: Get the table data result = [] data_frame = pandas_db.get_subframe(workflow.id, cond_filter) # Check if the values in the email column are correct emails try: correct_emails = all( [validate_email(x) for x in data_frame[column_name]]) if not correct_emails: # column has incorrect email addresses return 'The column with email addresses has incorrect values.' except TypeError: return 'The column with email addresses has incorrect values' for _, row in data_frame.iterrows(): # Get the dict(col_name, value) row_values = dict(zip(col_names, row)) # Step 3: Evaluate all the conditions condition_eval = {} for condition in Condition.objects.filter(action__id=action.id).values( 'is_filter', 'formula', 'name'): if condition['is_filter']: # Filter can be skipped in this stage continue # Evaluate the condition condition_eval[condition['name']] = \ dataops.formula_evaluation.evaluate_top_node( condition['formula'], row_values ) # Step 4: Create the context with the attributes, the evaluation of the # conditions and the values of the columns. attributes = workflow.attributes context = dict(dict(row_values, **condition_eval), **attributes) # Step 5: run the template with the given context # Render the text and append to result try: partial_result = [render_template(action.content, context, action)] except Exception as e: return 'Syntax error detected in the action text. ' + e.message # If there is extra message, render with context and create tuple if extra_string: try: partial_result.append(render_template(extra_string, context)) except Exception as e: return 'Syntax error detected in the subject. ' + e.message # If column_name was given (and it exists), create a tuple with that # element as the third component if col_idx != -1: partial_result.append(row_values[col_names[col_idx]]) # Append result result.append(partial_result) return result
def evaluate_action_canvas(action, extra_string, column_name): # Step 1: Get the workflow to access the data and prepare data workflow = Workflow.objects.get(pk=action.workflow.id) col_names = workflow.get_column_names() col_idx = -1 if column_name and column_name in col_names: col_idx = col_names.index(column_name) # Step 2: Get the row of data from the DB try: cond_filter = Condition.objects.get(action__id=action.id, is_filter=True) except ObjectDoesNotExist: cond_filter = None # Step 3: Get the table data result = [] data_frame = pandas_db.get_subframe(workflow.id, cond_filter) for _, row in data_frame.iterrows(): # Get the dict(col_name, value) row_values = dict(zip(col_names, row)) # Step 3: Evaluate all the conditions condition_eval = {} for condition in Condition.objects.filter( action__id=action.id ).values('is_filter', 'formula', 'name'): if condition['is_filter']: # Filter can be skipped in this stage continue # Evaluate the condition condition_eval[condition['name']] = \ dataops.formula_evaluation.evaluate_top_node( condition['formula'], row_values ) # Step 4: Create the context with the attributes, the evaluation of the # conditions and the values of the columns. attributes = workflow.attributes context = dict(dict(row_values, **condition_eval), **attributes) #print(list[context[col_names[col_idx]]]) # Step 5: run the template with the given context # Render the text and append to result try: partial_result = [render_template(action.content, context, action)] except Exception as e: return 'Syntax error detected in the action text. ' + e.message # If there is extra message, render with context and create tuple if extra_string: try: partial_result.append(render_template(extra_string, context)) except Exception as e: return 'Syntax error detected in the subject. ' + e.message # If column_name was given (and it exists), create a tuple with that # element as the third component if col_idx != -1: partial_result.append(row_values[col_names[col_idx]]) # Append result result.append(partial_result) return result