def execute_scheduled_actions_task(debug: bool):
    """Execute the entries in the DB that are due.

    :return: Nothing.
    """
    # Get the current date/time
    s_items = _get_pending_items()

    # If the number of tasks to execute is zero, we are done.
    if s_items.count() == 0:
        return

    for s_item in s_items:
        if debug:
            logger.info('Starting execution of task %s', str(s_item.id))

        with cache.lock(cache_lock_format.format(s_item.id)):
            # Item is now locked by the cache mechanism
            s_item.refresh_from_db()
            if s_item.status != ScheduledOperation.STATUS_PENDING:
                continue

            try:
                # Set item to running
                s_item.status = ScheduledOperation.STATUS_EXECUTING
                s_item.save()

                run_result = None
                log_item = None
                action_info = None

                # Get action info and log item
                if s_item.action.action_type in _function_distributor:
                    action_info, log_item = _function_distributor[
                        s_item.action.action_type](s_item)

                if log_item:
                    run_result = run_task(
                        s_item.user.id,
                        log_item.id,
                        action_info.get_store())
                    s_item.last_executed_log = log_item
                else:
                    logger.error(
                        'Execution of action type "%s" not implemented',
                        s_item.action.action_type)

                _update_item_status(s_item, run_result, debug)
            except Exception as exc:
                logger.error(
                    'Error while processing scheduled action: {0}'.format(
                        str(exc)))
Exemple #2
0
def execute_scheduled_actions_task(debug: bool):
    """Execute the entries in the DB that are due.

    :return: Nothing.
    """
    # Get the current date/time
    now = datetime.now(pytz.timezone(settings.TIME_ZONE))

    # Get all the actions that are pending
    s_items = ScheduledAction.objects.filter(
        status=ScheduledAction.STATUS_PENDING,
        execute__lt=now + timedelta(minutes=1))
    logger.info('%s actions pending execution', s_items.count())

    # If the number of tasks to execute is zero, we are done.
    if s_items.count() == 0:
        return

    for s_item in s_items:
        if debug:
            logger.info('Starting execution of task %s', str(s_item.id))

        # Set item to running
        s_item.status = ScheduledAction.STATUS_EXECUTING
        s_item.save()

        run_result = None
        log_item = None
        #
        # EMAIL ACTION
        #
        if s_item.action.action_type == Action.personalized_text:
            action_info = EmailPayload(s_item.payload)
            action_info['action_id'] = s_item.action_id
            action_info['item_column'] = s_item.item_column.name
            action_info['exclude_values'] = s_item.exclude_values

            # Log the event
            log_item = Log.objects.register(
                s_item.user, Log.SCHEDULE_EMAIL_EXECUTE,
                s_item.action.workflow, {
                    'action': s_item.action.name,
                    'action_id': s_item.action.id,
                    'bcc_email': s_item.payload.get('bcc_email'),
                    'cc_email': s_item.payload.get('cc_email'),
                    'item_column': s_item.item_column.name,
                    'execute': s_item.execute.isoformat(),
                    'exclude_values': s_item.exclude_values,
                    'from_email': s_item.user.email,
                    'send_confirmation':
                    s_item.payload.get('send_confirmation'),
                    'status': 'Preparing to execute',
                    'subject': s_item.payload.get('subject'),
                    'track_read': s_item.payload.get('track_read')
                })

            run_result = run_task(s_item.user.id, log_item.id,
                                  action_info.get_store())

        #
        # SEND LIST ACTION
        #
        elif s_item.action.action_type == Action.send_list:
            action_info = SendListPayload(s_item.payload)
            action_info['action_id'] = s_item.action_id

            # Log the event
            log_item = Log.objects.register(
                s_item.user, Log.SCHEDULE_SEND_LIST_EXECUTE,
                s_item.action.workflow, {
                    'action': s_item.action.name,
                    'action_id': s_item.action.id,
                    'from_email': s_item.user.email,
                    'email_to': s_item.payload.get('email_to'),
                    'subject': s_item.payload.get('subject'),
                    'bcc_email': s_item.payload.get('bcc_email'),
                    'cc_email': s_item.payload.get('cc_email'),
                    'execute': s_item.execute.isoformat(),
                    'status': 'Preparing to execute'
                })

            run_result = run_task(s_item.user.id, log_item.id,
                                  action_info.get_store())

        #
        # JSON action
        #
        elif s_item.action.action_type == Action.personalized_json:
            # Get the information about the keycolum
            item_column = None
            if s_item.item_column:
                item_column = s_item.item_column.name

            action_info = JSONPayload(s_item.payload)
            action_info['action_id'] = s_item.action_id
            action_info['item_column'] = item_column
            action_info['exclude_values'] = s_item.exclude_values

            # Log the event
            log_item = Log.objects.register(
                s_item.user, Log.SCHEDULE_JSON_EXECUTE, s_item.action.workflow,
                {
                    'action': s_item.action.name,
                    'action_id': s_item.action.id,
                    'exclude_values': s_item.exclude_values,
                    'item_column': item_column,
                    'status': 'Preparing to execute',
                    'target_url': s_item.action.target_url
                })

            # Send the objects
            run_result = run_task(s_item.user.id, log_item.id,
                                  action_info.get_store())

        #
        # JSON LIST action
        #
        elif s_item.action.action_type == Action.send_list_json:
            # Get the information about the keycolum
            item_column = None
            if s_item.item_column:
                item_column = s_item.item_column.name

            action_info = JSONPayload(s_item.payload)
            action_info['action_id'] = s_item.action_id

            # Log the event
            log_item = Log.objects.register(
                s_item.user, Log.SCHEDULE_JSON_EXECUTE, s_item.action.workflow,
                {
                    'action': s_item.action.name,
                    'action_id': s_item.action.id,
                    'status': 'Preparing to execute',
                    'target_url': s_item.action.target_url
                })

            # Send the objects
            run_result = run_task(s_item.user.id, log_item.id,
                                  action_info.get_store())

        #
        # Canvas Email Action
        #
        elif s_item.action.action_type == Action.personalized_canvas_email:
            # Get the information from the payload
            action_info = CanvasEmailPayload(s_item.payload)
            action_info['action_id'] = s_item.action_id
            action_info['item_column'] = s_item.item_column.name
            action_info['exclude_values'] = s_item.exclude_values

            # Log the event
            log_item = Log.objects.register(
                s_item.user, Log.SCHEDULE_EMAIL_EXECUTE,
                s_item.action.workflow, {
                    'action': s_item.action.name,
                    'action_id': s_item.action.id,
                    'item_column': s_item.item_column.name,
                    'execute': s_item.execute.isoformat(),
                    'exclude_values': s_item.exclude_values,
                    'from_email': s_item.user.email,
                    'status': 'Preparing to execute',
                    'subject': s_item.payload.get('subject', '')
                })

            run_result = run_task(s_item.user.id, log_item.id,
                                  action_info.get_store())
        else:
            logger.error('Execution of action type "%s" not implemented',
                         s_item.action.action_type)

        if run_result:
            s_item.status = ScheduledAction.STATUS_DONE
        else:
            s_item.status = ScheduledAction.STATUS_DONE_ERROR

        if debug:
            logger.info('Status set to %s', s_item.status)

        if log_item:
            # Store the log event in the scheduling item
            s_item.last_executed_log = log_item

        # Save the new status in the DB
        s_item.save()
def increase_track_count(method, get_dict):
    """
    Function to process track requests asynchronously.

    :param method: GET or POST received in the request
    :param get_dict: GET dictionary received in the request
    :return: If correct, increases one row of the DB by one
    """

    if method != 'GET':
        # Only GET requests are accepted
        logger.error(ugettext('Non-GET request received in Track URL'))
        return False

    # Obtain the track_id from the request
    track_id = get_dict.get('v')
    if not track_id:
        logger.error(ugettext('No track_id found in request'))
        # No track id, nothing to do
        return False

    # If the track_id is not correctly signed, finish.
    try:
        track_id = signing.loads(track_id)
    except signing.BadSignature:
        logger.error(ugettext('Bad signature in track_id'))
        return False

    # The request is legit and the value has been verified. Track_id has now
    # the dictionary with the tracking information

    # Get the objects related to the ping
    user = get_user_model().objects.filter(email=track_id['sender']).first()
    if not user:
        logger.error(
            ugettext('Incorrect user email {0}').format(track_id['sender'])
        )
        return False

    action = Action.objects.filter(pk=track_id['action']).first()
    if not action:
        logger.error(
            ugettext('Incorrect action id {0}').format(track_id['action'])
        )
        return False

    # Extract the relevant fields from the track_id
    column_dst = track_id.get('column_dst', '')
    column_to = track_id.get('column_to', '')
    msg_to = track_id.get('to', '')

    column = action.workflow.columns.filter(name=column_dst).first()
    if not column:
        # If the column does not exist, we are done
        logger.error(
            ugettext('Column {0} does not exist').format(column_dst)
        )
        return False

    log_payload = {'to': msg_to,
                   'email_column': column_to,
                   'column_dst': column_dst
                   }

    # If the track comes with column_dst, the event needs to be reflected
    # back in the data frame
    if column_dst:
        try:
            # Increase the relevant cell by one
            dataops.sql.row_queries.increase_row_integer(
                action.workflow.get_data_frame_table_name(),
                column_dst,
                column_to,
                msg_to
            )
        except Exception as e:
            log_payload['EXCEPTION_MSG'] = str(e)
        else:
            # Get the tracking column and update all the conditions in the
            # actions that have this column as part of their formulas
            # FIX: Too aggressive?
            track_col = action.workflow.columns.get(name=column_dst)
            for action in action.workflow.actions.all():
                action.update_n_rows_selected(track_col)

    # Record the event
    Log.objects.register(user,
                         Log.ACTION_EMAIL_READ,
                         action.workflow,
                         log_payload)

    return True