Ejemplo n.º 1
0
    def clear_restart_flag(self):
        """Clear the SERVER_RESTART_REQUIRED setting."""
        try:
            import common.models

            if common.models.InvenTreeSetting.get_setting(
                    'SERVER_RESTART_REQUIRED',
                    backup_value=False,
                    create=False,
                    cache=False):
                logger.info("Clearing SERVER_RESTART_REQUIRED flag")

                if not isImportingData():
                    common.models.InvenTreeSetting.set_setting(
                        'SERVER_RESTART_REQUIRED', False, None)
        except Exception:
            pass
Ejemplo n.º 2
0
def allow_table_event(table_name):
    """
    Determine if an automatic event should be fired for a given table.
    We *do not* want events to be fired for some tables!
    """

    if isImportingData():
        # Prevent table events during the data import process
        return False  # pragma: no cover

    table_name = table_name.lower().strip()

    # Ignore any tables which start with these prefixes
    ignore_prefixes = [
        'account_',
        'auth_',
        'authtoken_',
        'django_',
        'error_',
        'exchange_',
        'otp_',
        'plugin_',
        'socialaccount_',
        'user_',
        'users_',
    ]

    if any([table_name.startswith(prefix) for prefix in ignore_prefixes]):
        return False

    ignore_tables = [
        'common_notificationentry',
        'common_webhookendpoint',
        'common_webhookmessage',
    ]

    if table_name in ignore_tables:
        return False

    return True
Ejemplo n.º 3
0
def trigger_notifaction(obj, category=None, obj_ref='pk', **kwargs):
    """
    Send out a notification
    """

    targets = kwargs.get('targets', None)
    target_fnc = kwargs.get('target_fnc', None)
    target_args = kwargs.get('target_args', [])
    target_kwargs = kwargs.get('target_kwargs', {})
    context = kwargs.get('context', {})
    delivery_methods = kwargs.get('delivery_methods', None)

    # Check if data is importing currently
    if isImportingData():
        return

    # Resolve objekt reference
    obj_ref_value = getattr(obj, obj_ref)

    # Try with some defaults
    if not obj_ref_value:
        obj_ref_value = getattr(obj, 'pk')
    if not obj_ref_value:
        obj_ref_value = getattr(obj, 'id')
    if not obj_ref_value:
        raise KeyError(
            f"Could not resolve an object reference for '{str(obj)}' with {obj_ref}, pk, id"
        )

    # Check if we have notified recently...
    delta = timedelta(days=1)

    if NotificationEntry.check_recent(category, obj_ref_value, delta):
        logger.info(
            f"Notification '{category}' has recently been sent for '{str(obj)}' - SKIPPING"
        )
        return

    logger.info(f"Gathering users for notification '{category}'")
    # Collect possible targets
    if not targets:
        targets = target_fnc(*target_args, **target_kwargs)

    if targets:
        logger.info(f"Sending notification '{category}' for '{str(obj)}'")

        # Collect possible methods
        if delivery_methods is None:
            delivery_methods = storage.liste
        else:
            delivery_methods = (delivery_methods - IGNORED_NOTIFICATION_CLS)

        for method in delivery_methods:
            logger.info(f"Triggering method '{method.METHOD_NAME}'")
            try:
                deliver_notification(method, obj, category, targets, context)
            except NotImplementedError as error:
                raise error
            except Exception as error:
                logger.error(error)

        # Set delivery flag
        NotificationEntry.notify(category, obj_ref_value)
    else:
        logger.info(f"No possible users for notification '{category}'")
Ejemplo n.º 4
0
def trigger_notification(obj, category=None, obj_ref='pk', **kwargs):
    """Send out a notification."""
    targets = kwargs.get('targets', None)
    target_fnc = kwargs.get('target_fnc', None)
    target_args = kwargs.get('target_args', [])
    target_kwargs = kwargs.get('target_kwargs', {})
    target_exclude = kwargs.get('target_exclude', None)
    context = kwargs.get('context', {})
    delivery_methods = kwargs.get('delivery_methods', None)

    # Check if data is importing currently
    if isImportingData():
        return

    # Resolve object reference
    obj_ref_value = getattr(obj, obj_ref)

    # Try with some defaults
    if not obj_ref_value:
        obj_ref_value = getattr(obj, 'pk')
    if not obj_ref_value:
        obj_ref_value = getattr(obj, 'id')
    if not obj_ref_value:
        raise KeyError(
            f"Could not resolve an object reference for '{str(obj)}' with {obj_ref}, pk, id"
        )

    # Check if we have notified recently...
    delta = timedelta(days=1)

    if NotificationEntry.check_recent(category, obj_ref_value, delta):
        logger.info(
            f"Notification '{category}' has recently been sent for '{str(obj)}' - SKIPPING"
        )
        return

    logger.info(f"Gathering users for notification '{category}'")

    if target_exclude is None:
        target_exclude = set()

    # Collect possible targets
    if not targets:
        targets = target_fnc(*target_args, **target_kwargs)

    # Convert list of targets to a list of users
    # (targets may include 'owner' or 'group' classes)
    target_users = set()

    if targets:
        for target in targets:
            if target is None:
                continue
            # User instance is provided
            elif isinstance(target, get_user_model()):
                if target not in target_exclude:
                    target_users.add(target)
            # Group instance is provided
            elif isinstance(target, Group):
                for user in get_user_model().objects.filter(
                        groups__name=target.name):
                    if user not in target_exclude:
                        target_users.add(user)
            # Owner instance (either 'user' or 'group' is provided)
            elif isinstance(target, Owner):
                for owner in target.get_related_owners(include_group=False):
                    user = owner.owner
                    if user not in target_exclude:
                        target_users.add(user)
            # Unhandled type
            else:
                logger.error(
                    f"Unknown target passed to trigger_notification method: {target}"
                )

    if target_users:
        logger.info(f"Sending notification '{category}' for '{str(obj)}'")

        # Collect possible methods
        if delivery_methods is None:
            delivery_methods = storage.liste
        else:
            delivery_methods = (delivery_methods - IGNORED_NOTIFICATION_CLS)

        for method in delivery_methods:
            logger.info(
                f"Triggering notification method '{method.METHOD_NAME}'")
            try:
                deliver_notification(method, obj, category, target_users,
                                     context)
            except NotImplementedError as error:
                # Allow any single notification method to fail, without failing the others
                logger.error(error)
            except Exception as error:
                logger.error(error)

        # Set delivery flag
        NotificationEntry.notify(category, obj_ref_value)
    else:
        logger.info(f"No possible users for notification '{category}'")
Ejemplo n.º 5
0
def check_build_stock(build: build.models.Build):
    """Check the required stock for a newly created build order.

    Send an email out to any subscribed users if stock is low.
    """
    # Do not notify if we are importing data
    if isImportingData():
        return

    # Iterate through each of the parts required for this build

    lines = []

    if not build:
        logger.error("Invalid build passed to 'build.tasks.check_build_stock'")
        return

    try:
        part = build.part
    except part_models.Part.DoesNotExist:
        # Note: This error may be thrown during unit testing...
        logger.error(
            "Invalid build.part passed to 'build.tasks.check_build_stock'")
        return

    for bom_item in part.get_bom_items():

        sub_part = bom_item.sub_part

        # The 'in stock' quantity depends on whether the bom_item allows variants
        in_stock = sub_part.get_stock_count(
            include_variants=bom_item.allow_variants)

        allocated = sub_part.allocation_count()

        available = max(0, in_stock - allocated)

        required = Decimal(bom_item.quantity) * Decimal(build.quantity)

        if available < required:
            # There is not sufficient stock for this part

            lines.append({
                'link':
                InvenTree.helpers.construct_absolute_url(
                    sub_part.get_absolute_url()),
                'part':
                sub_part,
                'in_stock':
                in_stock,
                'allocated':
                allocated,
                'available':
                available,
                'required':
                required,
            })

    if len(lines) == 0:
        # Nothing to do
        return

    # Are there any users subscribed to these parts?
    subscribers = build.part.get_subscribers()

    emails = EmailAddress.objects.filter(user__in=subscribers, )

    if len(emails) > 0:

        logger.info(f"Notifying users of stock required for build {build.pk}")

        context = {
            'link':
            InvenTree.helpers.construct_absolute_url(build.get_absolute_url()),
            'build':
            build,
            'part':
            build.part,
            'lines':
            lines,
        }

        # Render the HTML message
        html_message = render_to_string(
            'email/build_order_required_stock.html', context)

        subject = _("Stock required for build order")

        recipients = emails.values_list('email', flat=True)

        InvenTree.tasks.send_email(subject,
                                   '',
                                   recipients,
                                   html_message=html_message)