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
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
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
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)
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
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), })
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)})