예제 #1
0
def send_sync_notifications(notification_id):
    """
    Given changed instance, calculate the history entry and
    a complete list for users to notify, send
    email to all users.
    """

    notification = HistoryChangeNotification.objects.select_for_update().get(pk=notification_id)
    # If the las modification is too recent we ignore it
    now = timezone.now()
    time_diff = now - notification.updated_datetime
    if time_diff.seconds < settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL:
        return

    history_entries = tuple(notification.history_entries.all().order_by("created_at"))
    obj, _ = get_last_snapshot_for_key(notification.key)
    obj_class = get_model_from_key(obj.key)

    context = {"obj_class": obj_class,
               "snapshot": obj.snapshot,
               "project": notification.project,
               "changer": notification.owner,
               "history_entries": history_entries}

    model = get_model_from_key(notification.key)
    template_name = _resolve_template_name(model, change_type=notification.history_type)
    email = _make_template_mail(template_name)

    for user in notification.notify_users.distinct():
        context["user"] = user
        context["lang"] = user.lang or settings.LANGUAGE_CODE
        email.send(user.email, context)

    notification.delete()
예제 #2
0
def send_sync_notifications(notification_id):
    """
    Given changed instance, calculate the history entry and
    a complete list for users to notify, send
    email to all users.
    """

    notification = HistoryChangeNotification.objects.select_for_update().get(pk=notification_id)
    # If the las modification is too recent we ignore it
    now = timezone.now()
    time_diff = now - notification.updated_datetime
    if time_diff.seconds < settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL:
        return

    history_entries = tuple(notification.history_entries.all().order_by("created_at"))
    obj, _ = get_last_snapshot_for_key(notification.key)
    obj_class = get_model_from_key(obj.key)

    context = {
               "obj_class": obj_class,
               "snapshot": obj.snapshot,
               "project": notification.project,
               "changer": notification.owner,
               "history_entries": history_entries}

    model = get_model_from_key(notification.key)
    template_name = _resolve_template_name(model, change_type=notification.history_type)
    email = _make_template_mail(template_name)

    for user in notification.notify_users.distinct():
        context["user"] = user
        email.send(user.email, context)

    notification.delete()
예제 #3
0
def send_sync_notifications(notification_id):
    """
    Given changed instance, calculate the history entry and
    a complete list for users to notify, send
    email to all users.
    """

    notification = HistoryChangeNotification.objects.select_for_update().get(pk=notification_id)
    # If the last modification is too recent we ignore it
    now = timezone.now()
    time_diff = now - notification.updated_datetime
    if time_diff.seconds < settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL:
        return

    history_entries = tuple(notification.history_entries.all().order_by("created_at"))
    obj, _ = get_last_snapshot_for_key(notification.key)
    obj_class = get_model_from_key(obj.key)

    context = {"obj_class": obj_class,
               "snapshot": obj.snapshot,
               "project": notification.project,
               "changer": notification.owner,
               "history_entries": history_entries}

    model = get_model_from_key(notification.key)
    template_name = _resolve_template_name(model, change_type=notification.history_type)
    email = _make_template_mail(template_name)
    domain = settings.SITES["api"]["domain"].split(":")[0] or settings.SITES["api"]["domain"]

    if "ref" in obj.snapshot:
        msg_id = obj.snapshot["ref"]
    elif "slug" in obj.snapshot:
        msg_id = obj.snapshot["slug"]
    else:
        msg_id = 'taiga-system'

    now = datetime.datetime.now()
    format_args = {
        "project_slug": notification.project.slug,
        "project_name": notification.project.name,
        "msg_id": msg_id,
        "time": int(now.timestamp()),
        "domain": domain
    }

    headers = {
        "Message-ID": "<{project_slug}/{msg_id}/{time}@{domain}>".format(**format_args),
        "In-Reply-To": "<{project_slug}/{msg_id}@{domain}>".format(**format_args),
        "References": "<{project_slug}/{msg_id}@{domain}>".format(**format_args),
        "List-ID": 'Taiga/{project_name} <taiga.{project_slug}@{domain}>'.format(**format_args),
        "Thread-Index": make_ms_thread_index("<{project_slug}/{msg_id}@{domain}>".format(**format_args), now)
    }

    for user in notification.notify_users.distinct():
        context["user"] = user
        context["lang"] = user.lang or settings.LANGUAGE_CODE
        email.send(user.email, context, headers=headers)

    notification.delete()
예제 #4
0
def on_new_history_entry(sender, instance, created, **kwargs):
    if instance._importing:
        return

    if instance.is_hidden:
        return None

    model = history_services.get_model_from_key(instance.key)
    pk = history_services.get_pk_from_key(instance.key)
    obj = model.objects.get(pk=pk)
    project = obj.project

    if instance.type == HistoryType.create:
        event_type = "create"
    elif instance.type == HistoryType.change:
        event_type = "change"
    elif instance.type == HistoryType.delete:
        event_type = "delete"

    user = User.objects.get(id=instance.user["pk"])

    extra_data = {
        "values_diff": instance.values_diff,
        "user": extract_user_info(user),
        "comment": instance.comment,
        "comment_html": instance.comment_html,
    }

    _push_to_timelines(project, user, obj, event_type, extra_data=extra_data)
def on_new_history_entry(sender, instance, created, **kwargs):
    if not created:
        return None

    if instance.is_hidden:
        return None

    model = history_service.get_model_from_key(instance.key)
    pk = history_service.get_pk_from_key(instance.key)
    obj = model.objects.get(pk=pk)

    hipchathooks = _get_project_hipchathooks(obj.project)

    if instance.type == HistoryType.create:
        task = tasks.create_hipchathook
        extra_args = []
    elif instance.type == HistoryType.change:
        task = tasks.change_hipchathook
        extra_args = [instance]
    elif instance.type == HistoryType.delete:
        task = tasks.delete_hipchathook
        extra_args = []

    for hipchathook in hipchathooks:
        args = [hipchathook["url"], hipchathook["notify"], obj] + extra_args

        if settings.CELERY_ENABLED:
            task.delay(*args)
        else:
            task(*args)
예제 #6
0
def on_new_history_entry(sender, instance, created, **kwargs):
    if not settings.WEBHOOKS_ENABLED:
        return None

    if instance.is_hidden:
        return None

    model = history_service.get_model_from_key(instance.key)
    pk = history_service.get_pk_from_key(instance.key)
    obj = model.objects.get(pk=pk)

    webhooks = _get_project_webhooks(obj.project)

    if instance.type == HistoryType.create:
        task = tasks.create_webhook
        extra_args = []
    elif instance.type == HistoryType.change:
        task = tasks.change_webhook
        extra_args = [instance]
    elif instance.type == HistoryType.delete:
        task = tasks.delete_webhook
        extra_args = [timezone.now()]

    for webhook in webhooks:
        args = [webhook["id"], webhook["url"], webhook["key"], obj
                ] + extra_args

        if settings.CELERY_ENABLED:
            task.delay(*args)
        else:
            task(*args)
예제 #7
0
def on_new_history_entry(sender, instance, created, **kwargs):
    if not settings.WEBHOOKS_ENABLED:
        return None

    if instance.is_hidden:
        return None

    model = history_service.get_model_from_key(instance.key)
    pk = history_service.get_pk_from_key(instance.key)
    obj = model.objects.get(pk=pk)

    webhooks = _get_project_webhooks(obj.project)

    if instance.type == HistoryType.create:
        task = tasks.create_webhook
        extra_args = []
    elif instance.type == HistoryType.change:
        task = tasks.change_webhook
        extra_args = [instance]
    elif instance.type == HistoryType.delete:
        task = tasks.delete_webhook
        extra_args = [timezone.now()]

    for webhook in webhooks:
        args = [webhook["id"], webhook["url"], webhook["key"], obj] + extra_args

        if settings.CELERY_ENABLED:
            connection.on_commit(lambda: task.delay(*args))
        else:
            connection.on_commit(lambda: task(*args))
def set_current_values_of_blocked_note_and_is_blocked_to_the_last_snapshot(
        apps, schema_editor):
    HistoryEntry = apps.get_model("history", "HistoryEntry")

    for history_entry in HistoryEntry.objects.filter(
            is_snapshot=True).order_by("created_at"):
        model = get_model_from_key(history_entry.key)
        pk = get_pk_from_key(history_entry.key)
        try:
            obj = model.objects.get(pk=pk)
            save = False
            if hasattr(obj, "is_blocked"
                       ) and "is_blocked" not in history_entry.snapshot:
                history_entry.snapshot["is_blocked"] = obj.is_blocked
                save = True

            if hasattr(obj, "blocked_note"
                       ) and "blocked_note" not in history_entry.snapshot:
                history_entry.snapshot["blocked_note"] = obj.blocked_note
                save = True

            if save:
                history_entry.save()

        except ObjectDoesNotExist as e:
            pass
예제 #9
0
def on_new_history_entry(sender, instance, created, **kwargs):
    if instance._importing:
        return

    if instance.is_hidden:
        return None

    model = history_services.get_model_from_key(instance.key)
    pk = history_services.get_pk_from_key(instance.key)
    obj = model.objects.get(pk=pk)
    project = obj.project

    if instance.type == HistoryType.create:
        event_type = "create"
    elif instance.type == HistoryType.change:
        event_type = "change"
    elif instance.type == HistoryType.delete:
        event_type = "delete"

    user = User.objects.get(id=instance.user["pk"])

    extra_data = {
        "values_diff": instance.values_diff,
        "user": extract_user_info(user),
        "comment": instance.comment,
        "comment_html": instance.comment_html,
    }

    _push_to_timelines(project, user, obj, event_type, extra_data=extra_data)
def on_new_history_entry(sender, instance, created, **kwargs):
    if not settings.WEBHOOKS_ENABLED:
        return None

    if instance.is_hidden:
        return None

    model = history_service.get_model_from_key(instance.key)
    pk = history_service.get_pk_from_key(instance.key)
    try:
        obj = model.objects.get(pk=pk)
    except model.DoesNotExist:
        # Catch simultaneous DELETE request
        return None

    webhooks = _get_project_webhooks(obj.project)

    if instance.type == HistoryType.create:
        task = tasks.create_webhook
        extra_args = []
    elif instance.type == HistoryType.change:
        task = tasks.change_webhook
        extra_args = [instance]
    elif instance.type == HistoryType.delete:
        task = tasks.delete_webhook
        extra_args = [timezone.now()]

    for webhook in webhooks:
        args = [webhook["id"], webhook["url"], webhook["key"], obj] + extra_args

        if settings.CELERY_ENABLED:
            connection.on_commit(lambda: task.delay(*args))
        else:
            connection.on_commit(lambda: task(*args))
예제 #11
0
def on_new_history_entry(sender, instance, created, **kwargs):
    if instance._importing:
        return

    if instance.is_hidden:
        return None

    if instance.user["pk"] is None:
        return None

    refresh_totals = getattr(instance, "refresh_totals", True)

    model = history_services.get_model_from_key(instance.key)
    pk = history_services.get_pk_from_key(instance.key)
    obj = model.objects.get(pk=pk)
    project = obj.project

    if instance.type == HistoryType.create:
        event_type = "create"
    elif instance.type == HistoryType.change:
        event_type = "change"
    elif instance.type == HistoryType.delete:
        event_type = "delete"

    user = get_user_model().objects.get(id=instance.user["pk"])
    values_diff = instance.values_diff
    _clean_description_fields(values_diff)

    extra_data = {
        "values_diff": values_diff,
        "user": extract_user_info(user),
        "comment": instance.comment,
        "comment_html": instance.comment_html,
    }

    # Detect deleted comment
    if instance.delete_comment_date:
        extra_data["comment_deleted"] = True

    # Detect edited comment
    if instance.comment_versions is not None and len(
            instance.comment_versions) > 0:
        extra_data["comment_edited"] = True

    created_datetime = instance.created_at
    _push_to_timelines(
        project,
        user,
        obj,
        event_type,
        created_datetime,
        extra_data=extra_data,
        refresh_totals=refresh_totals,
    )
예제 #12
0
def on_new_history_entry(sender, instance, created, **kwargs):
    if instance._importing:
        return

    if instance.is_hidden:
        return None

    if instance.user["pk"] is None:
        return None

    refresh_totals = getattr(instance, "refresh_totals", True)

    model = history_services.get_model_from_key(instance.key)
    pk = history_services.get_pk_from_key(instance.key)
    obj = model.objects.get(pk=pk)
    project = obj.project

    if instance.type == HistoryType.create:
        event_type = "create"
    elif instance.type == HistoryType.change:
        event_type = "change"
    elif instance.type == HistoryType.delete:
        event_type = "delete"

    user = get_user_model().objects.get(id=instance.user["pk"])
    values_diff = instance.values_diff
    _clean_description_fields(values_diff)

    extra_data = {
        "values_diff": values_diff,
        "user": extract_user_info(user),
        "comment": instance.comment,
        "comment_html": instance.comment_html,
    }

    # Detect deleted comment
    if instance.delete_comment_date:
        extra_data["comment_deleted"] = True

    # Detect edited comment
    if instance.comment_versions is not None and len(instance.comment_versions)>0:
        extra_data["comment_edited"] = True

    created_datetime = instance.created_at
    _push_to_timelines(project, user, obj, event_type, created_datetime, extra_data=extra_data, refresh_totals=refresh_totals)
def set_current_values_of_blocked_note_and_is_blocked_to_the_last_snapshot(apps, schema_editor):
    HistoryEntry = apps.get_model("history", "HistoryEntry")

    for history_entry in HistoryEntry.objects.filter(is_snapshot=True).order_by("created_at"):
        model = get_model_from_key(history_entry.key)
        pk = get_pk_from_key(history_entry.key)
        try:
            obj = model.objects.get(pk=pk)
            save = False
            if hasattr(obj, "is_blocked") and "is_blocked" not in history_entry.snapshot:
                history_entry.snapshot["is_blocked"] = obj.is_blocked
                save = True

            if hasattr(obj, "blocked_note") and "blocked_note" not in history_entry.snapshot:
                history_entry.snapshot["blocked_note"] = obj.blocked_note
                save = True

            if save:
                history_entry.save()

        except ObjectDoesNotExist as e:
            pass
예제 #14
0
def on_new_history_entry(sender, instance, created, **kwargs):
    if not settings.WEBHOOKS_ENABLED:
        return None

    if instance.is_hidden:
        return None

    model = history_service.get_model_from_key(instance.key)
    pk = history_service.get_pk_from_key(instance.key)
    try:
        obj = model.objects.get(pk=pk)
    except model.DoesNotExist:
        # Catch simultaneous DELETE request
        return None

    webhooks = _get_project_webhooks(obj.project)

    if instance.type == HistoryType.create:
        task = tasks.create_webhook
        extra_args = []
    elif instance.type == HistoryType.change:
        task = tasks.change_webhook
        extra_args = [instance]
    elif instance.type == HistoryType.delete:
        task = tasks.delete_webhook
        extra_args = []

    by = instance.owner
    date = timezone.now()

    for webhook in webhooks:
        args = [webhook["id"], webhook["url"], webhook["key"], by, date, obj] + extra_args

        if settings.CELERY_ENABLED:
            connection.on_commit(lambda: task.delay(*args))
        else:
            connection.on_commit(lambda: task(*args))
예제 #15
0
 def check_permissions(self, request, view, obj=None):
     model = get_model_from_key(obj.key)
     pk = get_pk_from_key(obj.key)
     project = model.objects.get(pk=pk)
     return is_project_admin(request.user, project)
예제 #16
0
 def check_permissions(self, request, view, obj=None):
     model = get_model_from_key(obj.key)
     pk = get_pk_from_key(obj.key)
     project = model.objects.get(pk=pk)
     return is_project_admin(request.user, project)
예제 #17
0
def send_sync_notifications(notification_id):
    """
    Given changed instance, calculate the history entry and
    a complete list for users to notify, send
    email to all users.
    """

    notification = HistoryChangeNotification.objects.select_for_update().get(pk=notification_id)

    # Custom Hardcode Filter
    if settings.NOTIFICATIONS_CUSTOM_FILTER:
        allowed_keys = [
            "userstories.userstory",
            "epics.epic",
            "issues.issue",
        ]

        if not any([(notification.key.find(key) >= 0) for key in allowed_keys]):
            notification.delete()
            return False, []

    # If the last modification is too recent we ignore it for the time being
    now = timezone.now()
    time_diff = now - notification.updated_datetime
    if time_diff.seconds < settings.CHANGE_NOTIFICATIONS_MIN_INTERVAL:
        return False, []

    # Custom Hardcode Filter
    qs = notification.history_entries
    if settings.NOTIFICATIONS_CUSTOM_FILTER:
        queries = [
            ~Q(comment=""),
            Q(key__startswith="epics.epic", type=HistoryType.create),
            Q(Q(key__startswith="userstories.userstory"), ~Q(values__users={}), ~Q(values__users=[])),
            Q(Q(key__startswith="issues.issue"), ~Q(values__users={}), ~Q(values__users=[])),
        ]
        query = queries.pop()
        for item in queries:
            query |= item

        qs = qs.filter(query).order_by("created_at")

    else:
        qs = qs.all()

    history_entries = tuple(qs)
    history_entries = list(squash_history_entries(history_entries))

    # If there are no effective modifications we can delete this notification
    # without further processing
    if notification.history_type == HistoryType.change and not history_entries:
        notification.delete()
        return False, []

    obj, _ = get_last_snapshot_for_key(notification.key)
    obj_class = get_model_from_key(obj.key)

    context = {"obj_class": obj_class,
               "snapshot": obj.snapshot,
               "project": notification.project,
               "changer": notification.owner,
               "history_entries": history_entries}

    model = get_model_from_key(notification.key)
    template_name = _resolve_template_name(model, change_type=notification.history_type)
    email = _make_template_mail(template_name)
    domain = settings.SITES["api"]["domain"].split(":")[0] or settings.SITES["api"]["domain"]

    if "ref" in obj.snapshot:
        msg_id = obj.snapshot["ref"]
    elif "slug" in obj.snapshot:
        msg_id = obj.snapshot["slug"]
    else:
        msg_id = 'taiga-system'

    now = datetime.datetime.now()
    project_name = remove_lr_cr(notification.project.name)
    format_args = {
        "unsubscribe_url": resolve_front_url('settings-mail-notifications'),
        "project_slug": notification.project.slug,
        "project_name": project_name,
        "msg_id": msg_id,
        "time": int(now.timestamp()),
        "domain": domain
    }

    headers = {
        "Message-ID": "<{project_slug}/{msg_id}/{time}@{domain}>".format(**format_args),
        "In-Reply-To": "<{project_slug}/{msg_id}@{domain}>".format(**format_args),
        "References": "<{project_slug}/{msg_id}@{domain}>".format(**format_args),
        "List-ID": 'Taiga/{project_name} <taiga.{project_slug}@{domain}>'.format(**format_args),
        "Thread-Index": make_ms_thread_index("<{project_slug}/{msg_id}@{domain}>".format(**format_args), now),
        "List-Unsubscribe": "<{unsubscribe_url}>".format(**format_args),
    }

    for user in notification.notify_users.distinct():
        context["user"] = user
        context["lang"] = user.lang or settings.LANGUAGE_CODE
        email.send(user.email, context, headers=headers)

    notification_id = notification.id
    notification.delete()
    return notification_id, history_entries