Skip to content

Commit

Permalink
Alerts: Add support for dismissing URL alerts
Browse files Browse the repository at this point in the history
While it works in most cases, there will be always cases when this
produces false results (force example with Cloudflare under attack mode
or when the target site requires authentication).

Fixes #4067
  • Loading branch information
nijel committed Jul 23, 2020
1 parent 274a91c commit ce0e19f
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 7 deletions.
14 changes: 12 additions & 2 deletions weblate/templates/component.html
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,18 @@
<div class="panel panel-default">
<div class="panel-heading">{{ alert }}</div>
<div class="panel-body">{{ alert.render }}</div>
{% comment %}Translators: Component alert footer, first and last contain localized human readable time span, for example 5 days ago{% endcomment %}
<div class="panel-footer">{% blocktrans with first=alert.timestamp|naturaltime last=alert.updated|naturaltime %}Appeared {{ first }}, last seen {{ last }}{% endblocktrans %}</div>
<form action="{% url "dismiss-alert" project=object.project.slug component=object.slug %}" method="post">
<div class="panel-footer">
{% comment %}Translators: Component alert footer, first and last contain localized human readable time span, for example 5 days ago{% endcomment %}
{% blocktrans with first=alert.timestamp|naturaltime last=alert.updated|naturaltime %}Appeared {{ first }}, last seen {{ last }}{% endblocktrans %}
{% if user_can_edit_component and alert.obj.dismissable %}
{% csrf_token %}
<input type="hidden" value="{{ alert.name }}" name="dismiss" />
<input type="submit" value="{% trans "Dismiss" %}" class="pull-right flip btn btn-danger" />
<div class="clearfix"></div>
{% endif %}
</div>
</form>
</div>
{% endfor %}
{% else %}
Expand Down
5 changes: 4 additions & 1 deletion weblate/templates/manage/alerts.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
<div class="panel-body">
<p>
{% for alert in items %}
<a href="{{ alert.component.get_absolute_url }}" class="btn btn-link">{{ alert.component }}</a>
<a href="{{ alert.component.get_absolute_url }}#alerts" class="btn btn-link">
{{ alert.component }}
{% if alert.dismissed %}<span class="badge">{% trans "dismissed" %}</span>{% endif %}
</a>
{% endfor %}
</p>
</div>
Expand Down
18 changes: 18 additions & 0 deletions weblate/trans/migrations/0092_alert_dismissed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.0.7 on 2020-07-23 12:24

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("trans", "0091_json_key"),
]

operations = [
migrations.AddField(
model_name="alert",
name="dismissed",
field=models.BooleanField(db_index=True, default=False),
),
]
4 changes: 4 additions & 0 deletions weblate/trans/models/alert.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Alert(models.Model):
timestamp = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=150)
dismissed = models.BooleanField(default=False, db_index=True)
details = JSONField(default={})

class Meta:
Expand Down Expand Up @@ -80,6 +81,7 @@ class BaseAlert:
verbose = ""
on_import = False
link_wide = False
dismissable = False

def __init__(self, instance):
self.instance = instance
Expand Down Expand Up @@ -266,6 +268,7 @@ def __init__(self, instance, vcs, file_format):
class BrokenBrowserURL(BaseAlert):
# Translators: Name of an alert
verbose = _("Broken repository browser URL")
dismissable = True

def __init__(self, instance, link, error):
super().__init__(instance)
Expand All @@ -277,6 +280,7 @@ def __init__(self, instance, link, error):
class BrokenProjectURL(BaseAlert):
# Translators: Name of an alert
verbose = _("Broken project website URL")
dismissable = True

def __init__(self, instance, error=None):
super().__init__(instance)
Expand Down
13 changes: 11 additions & 2 deletions weblate/trans/models/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,17 @@ class ComponentQuerySet(models.QuerySet):
# pylint: disable=no-init

def prefetch(self):
from weblate.trans.models import Alert

return self.prefetch_related(
"project", "linked_component", "linked_component__project", "alert_set"
"project",
"linked_component",
"linked_component__project",
models.Prefetch(
"alert_set",
queryset=Alert.objects.filter(dismissed=False),
to_attr="all_alerts",
),
)

def get_linked(self, val):
Expand Down Expand Up @@ -1568,7 +1577,7 @@ def update_source_checks(self):

@cached_property
def all_alerts(self):
result = self.alert_set.all()
result = self.alert_set.filter(dismissed=False)
list(result)
return result

Expand Down
10 changes: 9 additions & 1 deletion weblate/trans/models/translation.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,22 @@ def check_sync(self, component, lang, code, path, force=False, request=None):

class TranslationQuerySet(models.QuerySet):
def prefetch(self):
from weblate.trans.models import Alert

return self.prefetch_related(
"component",
"component__project",
"language",
"component__project__source_language",
"component__linked_component",
"component__linked_component__project",
).prefetch_related("language__plural_set", "component__alert_set")
"language__plural_set",
models.Prefetch(
"component__alert_set",
queryset=Alert.objects.filter(dismissed=False),
to_attr="all_alerts",
),
)

def filter_access(self, user):
if user.is_superuser:
Expand Down
2 changes: 1 addition & 1 deletion weblate/trans/templatetags/translations.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ def indicate_alerts(context, obj):
)
)

if component.all_alerts.exists():
if component.all_alerts:
result.append(
(
"state/alert.svg",
Expand Down
11 changes: 11 additions & 0 deletions weblate/trans/tests/test_alert.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"""Test for alerts."""

from django.test.utils import override_settings
from django.urls import reverse

from weblate.trans.tests.test_views import ViewTestCase

Expand All @@ -46,6 +47,16 @@ def test_duplicates(self):
alert.details["occurrences"][0]["source"], "Thank you for using Weblate."
)

def test_dismiss(self):
self.user.is_superuser = True
self.user.save()
response = self.client.post(
reverse("dismiss-alert", kwargs=self.kw_component),
{"dismiss": "BrokenBrowserURL"},
)
self.assertRedirects(response, self.component.get_absolute_url() + "#alerts")
self.assertTrue(self.component.alert_set.get(name="BrokenBrowserURL").dismissed)

def test_view(self):
response = self.client.get(self.component.get_absolute_url())
self.assertContains(response, "Duplicated translation")
Expand Down
17 changes: 17 additions & 0 deletions weblate/trans/views/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,23 @@ def change_component(request, project, component):
)


@never_cache
@login_required
@require_POST
def dismiss_alert(request, project, component):
obj = get_component(request, project, component)

if not request.user.has_perm("component.edit", obj):
raise Http404()

alert = obj.alert_set.get(name=request.POST["dismiss"])
if alert.obj.dismissable:
alert.dismissed = True
alert.save(update_fields=["dismissed"])

return redirect_param(obj, "#alerts")


@login_required
@require_POST
def remove_translation(request, project, component, lang):
Expand Down
6 changes: 6 additions & 0 deletions weblate/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,12 @@
weblate.trans.views.settings.move_component,
name="move",
),
# Alerts dismiss
path(
"alerts/<name:project>/<name:component>/dismiss/",
weblate.trans.views.settings.dismiss_alert,
name="dismiss-alert",
),
# Locking
path(
"lock/<name:project>/",
Expand Down

0 comments on commit ce0e19f

Please sign in to comment.