diff --git a/docs/changelog.rst b/docs/changelog.rst index eedfec7ae1..8436734f3c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,10 @@ CHANGELOG 2.108.0+dev (XXXX-XX-XX) ---------------------------- +**New features** + +- Add Annotation Categories to improve annotations on HD Views(refs #4032) + **Improvements** - Change infrastructure condition field to ManyToMany field (#3970) diff --git a/geotrek/api/tests/test_v2.py b/geotrek/api/tests/test_v2.py index 6f94d4dcfb..820b6e9ee6 100644 --- a/geotrek/api/tests/test_v2.py +++ b/geotrek/api/tests/test_v2.py @@ -57,6 +57,9 @@ from geotrek.zoning import models as zoning_models from geotrek.zoning.tests import factories as zoning_factory +ANNOTATION_CATEGORY_DETAIL_JSON_STRUCTURE = sorted([ + 'id', 'label', 'pictogram' +]) PAGINATED_JSON_STRUCTURE = sorted([ 'count', 'next', 'previous', 'results', @@ -488,6 +491,7 @@ def setUpTestData(cls): cls.hdviewpoint_site = common_factory.HDViewPointFactory( content_object=cls.site ) + cls.annotationcategory = common_factory.AnnotationCategoryFactory() def check_number_elems_response(self, response, model): json_response = response.json() @@ -829,6 +833,12 @@ def get_hdviewpoint_list(self, params=None): def get_hdviewpoint_detail(self, id_hdviewpoint, params=None): return self.client.get(reverse('apiv2:hdviewpoint-detail', args=(id_hdviewpoint,)), params) + def get_annotationcategory_list(self, params=None): + return self.client.get(reverse('apiv2:annotation-category-list'), params) + + def get_annotationcategory_detail(self, id_annotationcategory, params=None): + return self.client.get(reverse('apiv2:annotation-category-detail', args=(id_annotationcategory,)), params) + class NoPaginationTestCase(BaseApiTest): """ @@ -1502,6 +1512,18 @@ def test_hdviewpoint_list(self): common_models.HDViewPoint ) + def test_annotationcategory_detail(self): + self.check_structure_response( + self.get_annotationcategory_detail(self.annotationcategory.pk), + ANNOTATION_CATEGORY_DETAIL_JSON_STRUCTURE + ) + + def test_annotationcategory_list(self): + self.check_number_elems_response( + self.get_annotationcategory_list(), + common_models.AnnotationCategory + ) + def test_route_detail(self): self.check_structure_response( self.get_route_detail(self.route.pk), diff --git a/geotrek/api/v2/serializers.py b/geotrek/api/v2/serializers.py index 48e49eb109..2fa99a8459 100644 --- a/geotrek/api/v2/serializers.py +++ b/geotrek/api/v2/serializers.py @@ -926,6 +926,16 @@ class Meta: model = trekking_models.Theme fields = ('id', 'label', 'pictogram') + class AnnotationCategorySerializer(DynamicFieldsMixin, serializers.ModelSerializer): + label = serializers.SerializerMethodField() + + def get_label(self, obj): + return get_translation_or_dict('label', self, obj) + + class Meta: + model = common_models.AnnotationCategory + fields = ('id', 'label', 'pictogram') + class AccessibilitySerializer(DynamicFieldsMixin, serializers.ModelSerializer): name = serializers.SerializerMethodField() diff --git a/geotrek/api/v2/urls.py b/geotrek/api/v2/urls.py index c3c5228164..16145b5e47 100644 --- a/geotrek/api/v2/urls.py +++ b/geotrek/api/v2/urls.py @@ -15,6 +15,8 @@ router.register('label', api_views.LabelViewSet, basename='label') router.register('organism', api_views.OrganismViewSet, basename='organism') router.register('file_type', api_views.FileTypeViewSet, basename='filetype') +router.register('hdviewpoint', api_views.HDViewPointViewSet, basename='hdviewpoint') +router.register('annotation_category', api_views.AnnotationCategoryViewSet, basename='annotation-category') if 'geotrek.core' in settings.INSTALLED_APPS: router.register('path', api_views.PathViewSet, basename='path') if 'geotrek.infrastructure' in settings.INSTALLED_APPS: @@ -82,7 +84,6 @@ router.register('signage_color', api_views.ColorViewSet, basename='signage-color') router.register('signage_direction', api_views.DirectionViewSet, basename='signage-direction') router.register('signage_condition', api_views.SignageConditionViewSet, basename='signage-condition') - router.register('hdviewpoint', api_views.HDViewPointViewSet, basename='hdviewpoint') app_name = 'apiv2' diff --git a/geotrek/api/v2/views/__init__.py b/geotrek/api/v2/views/__init__.py index ecfd5ae948..1741b818c2 100644 --- a/geotrek/api/v2/views/__init__.py +++ b/geotrek/api/v2/views/__init__.py @@ -6,7 +6,7 @@ from geotrek import __version__ from .authent import StructureViewSet # noqa -from .common import TargetPortalViewSet, ThemeViewSet, SourceViewSet, ReservationSystemViewSet, LabelViewSet, OrganismViewSet, FileTypeViewSet, HDViewPointViewSet # noqa +from .common import TargetPortalViewSet, ThemeViewSet, SourceViewSet, ReservationSystemViewSet, LabelViewSet, OrganismViewSet, FileTypeViewSet, HDViewPointViewSet, AnnotationCategoryViewSet # noqa if 'geotrek.core' in settings.INSTALLED_APPS: from .core import PathViewSet # noqa if 'geotrek.feedback' in settings.INSTALLED_APPS: diff --git a/geotrek/api/v2/views/common.py b/geotrek/api/v2/views/common.py index a5f225fb29..0d4b9973cb 100644 --- a/geotrek/api/v2/views/common.py +++ b/geotrek/api/v2/views/common.py @@ -122,3 +122,9 @@ def get_queryset(self): .prefetch_related('content_object') \ .annotate(geom_transformed=Transform(F('geom'), settings.API_SRID)) \ .order_by('title') # Required for reliable pagination + + +class AnnotationCategoryViewSet(api_viewsets.GeotrekViewSet): + filter_backends = api_viewsets.GeotrekViewSet.filter_backends + serializer_class = api_serializers.AnnotationCategorySerializer + queryset = common_models.AnnotationCategory.objects.all() diff --git a/geotrek/common/admin.py b/geotrek/common/admin.py index 1d18e06417..e7ab7f47b0 100644 --- a/geotrek/common/admin.py +++ b/geotrek/common/admin.py @@ -84,6 +84,12 @@ class ThemeAdmin(MergeActionMixin, TabbedTranslationAdmin): merge_field = 'label' +class AnnotationCategoryAdmin(MergeActionMixin, TabbedTranslationAdmin): + list_display = ('label', 'pictogram_img') + search_fields = ('label',) + merge_field = 'label' + + class RecordSourceAdmin(admin.ModelAdmin): list_display = ('name', 'pictogram_img') search_fields = ('name', ) @@ -152,6 +158,7 @@ class AccessAdmin(MergeActionMixin, admin.ModelAdmin): admin.site.register(common_models.Attachment, AttachmentAdmin) admin.site.register(common_models.FileType, FileTypeAdmin) admin.site.register(common_models.Theme, ThemeAdmin) +admin.site.register(common_models.AnnotationCategory, AnnotationCategoryAdmin) admin.site.register(common_models.RecordSource, RecordSourceAdmin) admin.site.register(common_models.TargetPortal, TargetPortalAdmin) admin.site.register(common_models.ReservationSystem, ReservationSystemAdmin) diff --git a/geotrek/common/locale/de/LC_MESSAGES/django.po b/geotrek/common/locale/de/LC_MESSAGES/django.po index 0c97272b0a..e3389b0b1e 100644 --- a/geotrek/common/locale/de/LC_MESSAGES/django.po +++ b/geotrek/common/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-28 12:55+0000\n" +"POT-Creation-Date: 2024-07-23 13:20+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -340,6 +340,12 @@ msgstr "" msgid "HD Views" msgstr "" +msgid "Annotation category" +msgstr "" + +msgid "Annotation categories" +msgstr "" + msgid "Access mean" msgstr "" diff --git a/geotrek/common/locale/en/LC_MESSAGES/django.po b/geotrek/common/locale/en/LC_MESSAGES/django.po index 0c97272b0a..e3389b0b1e 100644 --- a/geotrek/common/locale/en/LC_MESSAGES/django.po +++ b/geotrek/common/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-28 12:55+0000\n" +"POT-Creation-Date: 2024-07-23 13:20+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -340,6 +340,12 @@ msgstr "" msgid "HD Views" msgstr "" +msgid "Annotation category" +msgstr "" + +msgid "Annotation categories" +msgstr "" + msgid "Access mean" msgstr "" diff --git a/geotrek/common/locale/es/LC_MESSAGES/django.po b/geotrek/common/locale/es/LC_MESSAGES/django.po index d0e547039a..6756360c77 100644 --- a/geotrek/common/locale/es/LC_MESSAGES/django.po +++ b/geotrek/common/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-28 12:55+0000\n" +"POT-Creation-Date: 2024-07-23 13:20+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Olivia Duval \n" "Language-Team: LANGUAGE \n" @@ -340,6 +340,12 @@ msgstr "" msgid "HD Views" msgstr "" +msgid "Annotation category" +msgstr "" + +msgid "Annotation categories" +msgstr "" + msgid "Access mean" msgstr "" diff --git a/geotrek/common/locale/fr/LC_MESSAGES/django.po b/geotrek/common/locale/fr/LC_MESSAGES/django.po index 23d21ede68..cf9a25a571 100644 --- a/geotrek/common/locale/fr/LC_MESSAGES/django.po +++ b/geotrek/common/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-28 12:55+0000\n" +"POT-Creation-Date: 2024-07-23 13:20+0000\n" "PO-Revision-Date: 2020-09-23 07:10+0000\n" "Last-Translator: Emmanuelle Helly \n" "Language-Team: French \n" "Language-Team: LANGUAGE \n" @@ -340,6 +340,12 @@ msgstr "" msgid "HD Views" msgstr "" +msgid "Annotation category" +msgstr "" + +msgid "Annotation categories" +msgstr "" + msgid "Access mean" msgstr "" diff --git a/geotrek/common/locale/nl/LC_MESSAGES/django.po b/geotrek/common/locale/nl/LC_MESSAGES/django.po index 0c97272b0a..e3389b0b1e 100644 --- a/geotrek/common/locale/nl/LC_MESSAGES/django.po +++ b/geotrek/common/locale/nl/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-28 12:55+0000\n" +"POT-Creation-Date: 2024-07-23 13:20+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -340,6 +340,12 @@ msgstr "" msgid "HD Views" msgstr "" +msgid "Annotation category" +msgstr "" + +msgid "Annotation categories" +msgstr "" + msgid "Access mean" msgstr "" diff --git a/geotrek/common/migrations/0037_annotationcategory.py b/geotrek/common/migrations/0037_annotationcategory.py new file mode 100644 index 0000000000..04e28c8727 --- /dev/null +++ b/geotrek/common/migrations/0037_annotationcategory.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.13 on 2024-07-23 13:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0036_accessmean'), + ] + + operations = [ + migrations.CreateModel( + name='AnnotationCategory', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date_insert', models.DateTimeField(auto_now_add=True, verbose_name='Insertion date')), + ('date_update', models.DateTimeField(auto_now=True, db_index=True, verbose_name='Update date')), + ('pictogram', models.FileField(max_length=512, null=True, upload_to='upload', verbose_name='Pictogram')), + ('label', models.CharField(max_length=128, verbose_name='Name')), + ], + options={ + 'verbose_name': 'Annotation category', + 'verbose_name_plural': 'Annotation categories', + 'ordering': ['label'], + }, + ), + ] diff --git a/geotrek/common/models.py b/geotrek/common/models.py index 38623e6d6b..5c0058bdf7 100755 --- a/geotrek/common/models.py +++ b/geotrek/common/models.py @@ -382,6 +382,18 @@ def get_annotate_url(self): return reverse('common:hdviewpoint_annotate', args=[self.pk]) +class AnnotationCategory(TimeStampedModelMixin, PictogramMixin): + label = models.CharField(verbose_name=_("Name"), max_length=128) + + class Meta: + verbose_name = _("Annotation category") + verbose_name_plural = _("Annotation categories") + ordering = ['label'] + + def __str__(self): + return self.label + + class AccessMean(TimeStampedModelMixin): label = models.CharField(max_length=128) diff --git a/geotrek/common/tests/factories.py b/geotrek/common/tests/factories.py index 380d24ab37..f07b6d729e 100644 --- a/geotrek/common/tests/factories.py +++ b/geotrek/common/tests/factories.py @@ -174,3 +174,11 @@ class Meta: model = models.AccessMean label = factory.Sequence(lambda n: "Acces mean %s" % n) + + +class AnnotationCategoryFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.AnnotationCategory + + label = factory.Sequence(lambda n: "Annotation Type %s" % n) + pictogram = factory.django.ImageField() diff --git a/geotrek/common/translation.py b/geotrek/common/translation.py index 8d6415121b..eff4a25ea3 100644 --- a/geotrek/common/translation.py +++ b/geotrek/common/translation.py @@ -1,12 +1,16 @@ from modeltranslation.translator import translator, TranslationOptions -from geotrek.common.models import TargetPortal, Theme, Label, HDViewPoint +from geotrek.common.models import AnnotationCategory, TargetPortal, Theme, Label, HDViewPoint class ThemeTO(TranslationOptions): fields = ('label', ) +class AnnotationCategoryTO(TranslationOptions): + fields = ('label', ) + + class TargetPortalTO(TranslationOptions): fields = ('title', 'description') @@ -22,4 +26,5 @@ class HDViewPointTO(TranslationOptions): translator.register(Theme, ThemeTO) translator.register(TargetPortal, TargetPortalTO) translator.register(Label, LabelTO) +translator.register(AnnotationCategory, AnnotationCategoryTO) translator.register(HDViewPoint, HDViewPointTO)