diff --git a/docs/changelog.rst b/docs/changelog.rst index 0a0e9dc9ad..aa8f04a48d 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 Type to categorize annotations on HD Views(refs #4032)" + **Bug fixes** - Fix empty linetring in reorder_topology cmd (fixes #4092) diff --git a/geotrek/api/tests/test_v2.py b/geotrek/api/tests/test_v2.py index 7cc9801135..21a75e2d93 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_TYPE_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.annotationtype = common_factory.AnnotationTypeFactory() 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_annotationtype_list(self, params=None): + return self.client.get(reverse('apiv2:annotation-type-list'), params) + + def get_annotationtype_detail(self, id_annotationtype, params=None): + return self.client.get(reverse('apiv2:annotation-type-detail', args=(id_annotationtype,)), params) + class NoPaginationTestCase(BaseApiTest): """ @@ -1502,6 +1512,18 @@ def test_hdviewpoint_list(self): common_models.HDViewPoint ) + def test_annotationtype_detail(self): + self.check_structure_response( + self.get_annotationtype_detail(self.annotationtype.pk), + ANNOTATION_TYPE_DETAIL_JSON_STRUCTURE + ) + + def test_annotationtype_list(self): + self.check_number_elems_response( + self.get_annotationtype_list(), + common_models.AnnotationType + ) + 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 85134816d9..ed0d5a0e0e 100644 --- a/geotrek/api/v2/serializers.py +++ b/geotrek/api/v2/serializers.py @@ -924,6 +924,18 @@ class Meta: model = trekking_models.Theme fields = ('id', 'label', 'pictogram') + + class AnnotationTypeSerializer(DynamicFieldsMixin, serializers.ModelSerializer): + label = serializers.SerializerMethodField() + + def get_label(self, obj): + return get_translation_or_dict('label', self, obj) + + class Meta: + model = common_models.AnnotationType + 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..02ae4780da 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_type', api_views.AnnotationTypeViewSet, basename='annotation-type') 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..dc544b4cab 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, AnnotationTypeViewSet # 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..60d4d182a3 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 AnnotationTypeViewSet(api_viewsets.GeotrekViewSet): + filter_backends = api_viewsets.GeotrekViewSet.filter_backends + serializer_class = api_serializers.AnnotationTypeSerializer + queryset = common_models.AnnotationType.objects.all() diff --git a/geotrek/common/admin.py b/geotrek/common/admin.py index 1d18e06417..8cdd18d875 100644 --- a/geotrek/common/admin.py +++ b/geotrek/common/admin.py @@ -84,6 +84,12 @@ class ThemeAdmin(MergeActionMixin, TabbedTranslationAdmin): merge_field = 'label' +class AnnotationTypeAdmin(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.AnnotationType, AnnotationTypeAdmin) 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..92e55aa5cf 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 10:42+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 type" +msgstr "" + +msgid "Annotation types" +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..92e55aa5cf 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 10:42+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 type" +msgstr "" + +msgid "Annotation types" +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..b172874f4d 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 10:42+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 type" +msgstr "" + +msgid "Annotation types" +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..f99fdd9900 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 10:38+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 type" +msgstr "" + +msgid "Annotation types" +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..92e55aa5cf 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 10:42+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 type" +msgstr "" + +msgid "Annotation types" +msgstr "" + msgid "Access mean" msgstr "" diff --git a/geotrek/common/migrations/0037_annotationtype.py b/geotrek/common/migrations/0037_annotationtype.py new file mode 100644 index 0000000000..8beb57076b --- /dev/null +++ b/geotrek/common/migrations/0037_annotationtype.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.13 on 2024-07-23 10:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0036_accessmean'), + ] + + operations = [ + migrations.CreateModel( + name='AnnotationType', + 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 Type', + 'verbose_name_plural': 'Annotation Types', + 'ordering': ['label'], + }, + ), + ] diff --git a/geotrek/common/models.py b/geotrek/common/models.py index 38623e6d6b..6671106735 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 AnnotationType(TimeStampedModelMixin, PictogramMixin): + label = models.CharField(verbose_name=_("Name"), max_length=128) + + class Meta: + verbose_name = _("Annotation type") + verbose_name_plural = _("Annotation types") + 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..bbe8a3c89d 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 AnnotationTypeFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.AnnotationType + + 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..8d8e937e46 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 AnnotationType, TargetPortal, Theme, Label, HDViewPoint class ThemeTO(TranslationOptions): fields = ('label', ) +class AnnotationTypeTO(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(AnnotationType, AnnotationTypeTO) translator.register(HDViewPoint, HDViewPointTO)