Skip to content

Commit

Permalink
feat(add-ons): add indication of other scopes to add-on list
Browse files Browse the repository at this point in the history
Without that users can be confused that their previously installed
add-ons are gone.

Fixes #11539
  • Loading branch information
nijel committed May 2, 2024
1 parent f4739eb commit 8b9eb31
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 15 deletions.
1 change: 1 addition & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Not yet released.
**Improvements**

* Improved performance of rendering large lists of objects.
* Added links to manage other scope :ref:`addons`.

**Bug fixes**

Expand Down
34 changes: 25 additions & 9 deletions weblate/addons/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -695,23 +695,31 @@ def test_add_simple(self) -> None:
{"name": "weblate.gettext.authors"},
follow=True,
)
self.assertContains(response, "1 add-on installed")
self.assertContains(response, "Installed 1 add-on")

def test_add_simple_project_addon(self) -> None:
response = self.client.post(
reverse("addons", kwargs=self.kw_project_path),
{"name": "weblate.consistency.languages"},
follow=True,
)
self.assertContains(response, "1 add-on installed")
self.assertContains(response, "Installed 1 add-on")

def test_add_simple_site_wide_addon(self) -> None:
response = self.client.post(
reverse("manage-addons"),
{"name": "weblate.consistency.languages"},
follow=True,
)
self.assertContains(response, "1 add-on installed")
self.assertEqual(response.status_code, 403)
self.user.is_superuser = True
self.user.save()
response = self.client.post(
reverse("manage-addons"),
{"name": "weblate.consistency.languages"},
follow=True,
)
self.assertContains(response, "Installed 1 add-on")

def test_add_invalid(self) -> None:
response = self.client.post(
Expand All @@ -738,9 +746,17 @@ def test_add_config(self) -> None:
},
follow=True,
)
self.assertContains(response, "1 add-on installed")
self.assertContains(response, "Installed 1 add-on")

def test_add_config_site_wide_addon(self) -> None:
response = self.client.post(
reverse("manage-addons"),
{"name": "weblate.generate.generate"},
follow=True,
)
self.assertEqual(response.status_code, 403)
self.user.is_superuser = True
self.user.save()
response = self.client.post(
reverse("manage-addons"),
{"name": "weblate.generate.generate"},
Expand All @@ -757,7 +773,7 @@ def test_add_config_site_wide_addon(self) -> None:
},
follow=True,
)
self.assertContains(response, "1 add-on installed")
self.assertContains(response, "Installed 1 add-on")

def test_add_pseudolocale(self) -> None:
response = self.client.post(
Expand All @@ -776,7 +792,7 @@ def test_add_pseudolocale(self) -> None:
},
follow=True,
)
self.assertContains(response, "1 add-on installed")
self.assertContains(response, "Installed 1 add-on")

def test_edit_config(self) -> None:
self.test_add_config()
Expand All @@ -792,7 +808,7 @@ def test_delete(self) -> None:
response = self.client.post(
addon.instance.get_absolute_url(), {"delete": "1"}, follow=True
)
self.assertContains(response, "no add-ons currently installed")
self.assertContains(response, "No add-ons currently installed")


class PropertiesAddonTest(ViewTestCase):
Expand Down Expand Up @@ -1069,7 +1085,7 @@ def test_form(self) -> None:
},
follow=True,
)
self.assertContains(response, "1 add-on installed")
self.assertContains(response, "Installed 1 add-on")


class ScriptsTest(TestAddonMixin, ViewTestCase):
Expand Down Expand Up @@ -1330,7 +1346,7 @@ def test_create(self) -> None:
},
follow=True,
)
self.assertContains(response, "1 add-on installed")
self.assertContains(response, "Installed 1 add-on")


class CDNJSAddonTest(ViewTestCase):
Expand Down
16 changes: 16 additions & 0 deletions weblate/addons/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def get_queryset(self):
self.kwargs["project_obj"] = self.path_object
return Addon.objects.filter_project(self.path_object)

if not self.request.user.has_perm("management.addons"):
raise PermissionDenied("Can not manage add-ons")
return Addon.objects.filter_sitewide()

def get_success_url(self):
Expand Down Expand Up @@ -59,6 +61,10 @@ def get_context_data(self, **kwargs):
),
key=lambda x: x.name,
)
result["scope"] = "component"
result["project_addons"] = Addon.objects.filter_project(
target.project
).count()
else:
# This covers both project-wide and site-wide
result["available"] = sorted(
Expand All @@ -69,6 +75,10 @@ def get_context_data(self, **kwargs):
),
key=lambda x: x.name,
)
result["scope"] = "sitewide" if target is None else "project"

if target is not None:
result["sitewide_addons"] = Addon.objects.filter_sitewide().count()

return result

Expand Down Expand Up @@ -165,6 +175,12 @@ def get_object(self):
raise PermissionDenied("Can not edit component")
if obj.project and not self.request.user.has_perm("project.edit", obj.project):
raise PermissionDenied("Can not edit project")
if (
obj.project is None
and obj.component is None
and not self.request.user.has_perm("management.addons")
):
raise PermissionDenied("Can not manage add-ons")
return obj

def post(self, request, *args, **kwargs):
Expand Down
2 changes: 2 additions & 0 deletions weblate/auth/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@
("componentlist.edit", gettext_noop("Manage component lists")),
# Translators: Permission name
("billing.manage", gettext_noop("Manage billing")),
# Translators: Permission name
("management.addons", gettext_noop("Manage site-wide add-ons")),
)

GLOBAL_PERM_NAMES = {perm[0] for perm in GLOBAL_PERMISSIONS}
Expand Down
25 changes: 19 additions & 6 deletions weblate/templates/addons/addon_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@
<div class="panel panel-default">
<div class="panel-heading"><h4 class="panel-title">
{% documentation_icon 'admin/addons' right=True %}
{% trans "Installed add-ons" %}
{% if not object_list %}
{% trans "No add-ons currently installed" %}
{% else %}
{% blocktrans count count=object_list|length %}Installed {{ count }} add-on{% plural %}Installed {{ count }} add-ons{% endblocktrans %}
{% endif %}
</h4></div>
<table class="table table-striped">
<tbody>
Expand All @@ -41,11 +45,20 @@
</tbody>
</table>
<div class="panel-footer">
{% if not object_list %}
{% trans "There are no add-ons currently installed." %}
{% else %}
{% blocktrans count count=object_list|length %}There is currently {{ count }} add-on installed.{% plural %}There are currently {{ count }} add-ons installed.{% endblocktrans %}
{% endif %}
{% if scope == "sitewide" %}
{% trans "Add-ons can be installed on project and component scope as well." %}
{% endif %}
{% if scope == "component" %}
<a href="{% url 'addons' path=object.project.get_url_path %}" class="btn btn-primary">
{% blocktrans count count=project_addons %}Manage project-wide add-ons ({{ count }} installed){% plural %}Manage project-wide add-ons ({{ count }} installed){% endblocktrans %}
</a>
{% endif %}
{% if scope == "project" or scope == "component" %}
{% perm "management.addons" as user_can_manage_addons %}
<a href="{% url 'manage-addons' %}" class="btn btn-primary" {% if not user_can_manage_addons %}disabled="disabled"{% endif %}>
{% blocktrans count count=sitewide_addons %}Manage site-wide add-ons ({{ count }} installed){% plural %}Manage site-wide add-ons ({{ count }} installed){% endblocktrans %}
</a>
{% endif %}
</div>
</div>

Expand Down

0 comments on commit 8b9eb31

Please sign in to comment.