diff --git a/umap/migrations/0022_map_group_alter_datalayer_edit_status_and_more.py b/umap/migrations/0022_map_group_alter_datalayer_edit_status_and_more.py index bea2ef72..511a8678 100644 --- a/umap/migrations/0022_map_group_alter_datalayer_edit_status_and_more.py +++ b/umap/migrations/0022_map_group_alter_datalayer_edit_status_and_more.py @@ -1,9 +1,10 @@ # Generated by Django 5.1 on 2024-08-15 11:33 import django.db.models.deletion -import umap.models from django.db import migrations, models +import umap.models + class Migration(migrations.Migration): dependencies = [ diff --git a/umap/models.py b/umap/models.py index fe3e3753..d4fbae30 100644 --- a/umap/models.py +++ b/umap/models.py @@ -37,7 +37,7 @@ def get_user_stars_url(self): def get_group_url(self): - return "TODO" + return reverse("group_maps", kwargs={"pk": self.pk}) def get_group_metadata(self): @@ -268,6 +268,9 @@ class Map(NamedModel): path = reverse("map_anonymous_edit_url", kwargs={"signature": signature}) return settings.SITE_URL + path + def get_author(self): + return self.group or self.owner + def is_owner(self, user=None, request=None): if user and self.owner == user: return True diff --git a/umap/static/umap/js/modules/caption.js b/umap/static/umap/js/modules/caption.js index 36c63c4c..5496688b 100644 --- a/umap/static/umap/js/modules/caption.js +++ b/umap/static/umap/js/modules/caption.js @@ -20,7 +20,7 @@ export default class Caption { const container = DomUtil.create('div', 'umap-caption') const hgroup = DomUtil.element({ tagName: 'hgroup', parent: container }) DomUtil.createTitle(hgroup, this.map.options.name, 'icon-caption icon-block') - this.map.permissions.addOwnerLink('h4', hgroup) + this.map.addAuthorLink('h4', hgroup) if (this.map.options.description) { const description = DomUtil.element({ tagName: 'div', diff --git a/umap/static/umap/js/modules/permissions.js b/umap/static/umap/js/modules/permissions.js index 5c6c20c2..58c230a7 100644 --- a/umap/static/umap/js/modules/permissions.js +++ b/umap/static/umap/js/modules/permissions.js @@ -189,23 +189,6 @@ export class MapPermissions { }) } - addOwnerLink(element, container) { - if (this.options.owner?.name && this.options.owner.url) { - const ownerContainer = DomUtil.add( - element, - 'umap-map-owner', - container, - ` ${translate('by')} ` - ) - DomUtil.createLink( - '', - ownerContainer, - this.options.owner.name, - this.options.owner.url - ) - } - } - commit() { this.map.options.permissions = Object.assign( this.map.options.permissions, diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js index 0e060182..3493e082 100644 --- a/umap/static/umap/js/umap.js +++ b/umap/static/umap/js/umap.js @@ -1582,7 +1582,7 @@ U.Map = L.Map.extend({ ) const name = L.DomUtil.create('h3', '', container) L.DomEvent.disableClickPropagation(container) - this.permissions.addOwnerLink('span', container) + this.addAuthorLink('span', container) if (this.getOption('captionMenus')) { L.DomUtil.createButton( 'umap-about-link flat', @@ -1887,4 +1887,21 @@ U.Map = L.Map.extend({ .filter((val, idx, arr) => arr.indexOf(val) === idx) .sort(U.Utils.naturalSort) }, + + addAuthorLink: function (element, container) { + if (this.options.author?.name) { + const authorContainer = L.DomUtil.add( + element, + 'umap-map-author', + container, + ` ${L._('by')} ` + ) + L.DomUtil.createLink( + '', + authorContainer, + this.options.author.name, + this.options.author.url + ) + } + }, }) diff --git a/umap/static/umap/map.css b/umap/static/umap/map.css index 6db07c63..8bbb455c 100644 --- a/umap/static/umap/map.css +++ b/umap/static/umap/map.css @@ -922,7 +922,7 @@ a.umap-control-caption, .datalayer-name { cursor: pointer; } -.umap-caption .umap-map-owner { +.umap-caption .umap-map-author { padding-inline-start: 31px; } diff --git a/umap/templates/umap/map_list.html b/umap/templates/umap/map_list.html index 76948266..9e7f7f3e 100644 --- a/umap/templates/umap/map_list.html +++ b/umap/templates/umap/map_list.html @@ -6,9 +6,9 @@ {% map_fragment map_inst prefix=prefix page=request.GET.p %}
{{ map_inst.name }} - {% if map_inst.owner %} - {% trans "by" %} {{ map_inst.owner }} - {% endif %} + {% with author=map_inst.get_author %} + {% trans "by" %} {{ author }} + {% endwith %}
{% endfor %} diff --git a/umap/tests/integration/test_caption.py b/umap/tests/integration/test_caption.py index 1458a8a3..e5f2b7eb 100644 --- a/umap/tests/integration/test_caption.py +++ b/umap/tests/integration/test_caption.py @@ -25,3 +25,23 @@ def test_caption(live_server, page, map): panel.locator(".datalayer-legend .off").get_by_text(non_loaded.name) ).to_be_visible() expect(panel.locator(".datalayer-legend").get_by_text(hidden.name)).to_be_hidden() + + +def test_caption_should_display_owner_as_author(live_server, page, map): + map.settings["properties"]["onLoadPanel"] = "caption" + map.save() + page.goto(f"{live_server.url}{map.get_absolute_url()}") + panel = page.locator(".panel.left.on") + expect(panel).to_be_visible() + expect(panel.get_by_text("By Gabriel")).to_be_visible() + + +def test_caption_should_display_group_as_author(live_server, page, map, group): + map.settings["properties"]["onLoadPanel"] = "caption" + map.group = group + map.save() + page.goto(f"{live_server.url}{map.get_absolute_url()}") + panel = page.locator(".panel.left.on") + expect(panel).to_be_visible() + expect(panel.get_by_text("By Gabriel")).to_be_hidden() + expect(panel.get_by_text("By Awesome Group")).to_be_visible() diff --git a/umap/urls.py b/umap/urls.py index ecc9353a..2a39fe6b 100644 --- a/umap/urls.py +++ b/umap/urls.py @@ -187,6 +187,7 @@ urlpatterns += i18n_patterns( re_path(r"^about/$", views.about, name="about"), re_path(r"^user/(?P.+)/stars/$", views.user_stars, name="user_stars"), re_path(r"^user/(?P.+)/$", views.user_maps, name="user_maps"), + path("group//", views.group_maps, name="group_maps"), re_path(r"", include(i18n_urls)), ) urlpatterns += ( diff --git a/umap/views.py b/umap/views.py index 50a0dd0c..b55c9020 100644 --- a/umap/views.py +++ b/umap/views.py @@ -18,6 +18,7 @@ from django.conf import settings from django.contrib import messages from django.contrib.auth import get_user_model from django.contrib.auth import logout as do_logout +from django.contrib.auth.models import Group from django.contrib.gis.measure import D from django.contrib.postgres.search import SearchQuery, SearchVector from django.contrib.staticfiles.storage import staticfiles_storage @@ -247,6 +248,24 @@ class UserStars(UserMaps): user_stars = UserStars.as_view() +class GroupMaps(PaginatorMixin, DetailView): + model = Group + list_template_name = "umap/map_list.html" + context_object_name = "current_group" + + def get_maps(self): + return Map.public.filter(group=self.object).order_by("-modified_at") + + def get_context_data(self, **kwargs): + kwargs.update( + {"maps": self.paginate(self.get_maps(), settings.UMAP_MAPS_PER_PAGE)} + ) + return super().get_context_data(**kwargs) + + +group_maps = GroupMaps.as_view() + + class SearchMixin: def get_search_queryset(self, **kwargs): q = self.request.GET.get("q") @@ -673,6 +692,12 @@ class MapView(MapDetailMixin, PermissionsMixin, DetailView): map_settings["properties"] = {} map_settings["properties"]["name"] = self.object.name map_settings["properties"]["permissions"] = self.get_permissions() + author = self.object.get_author() + if author: + map_settings["properties"]["author"] = { + "name": str(author), + "url": author.get_url(), + } return map_settings def is_starred(self):