diff --git a/docs/changelog.rst b/docs/changelog.rst index bf97639d..416d28c4 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,16 @@ CHANGELOG ========= +1.1.0+dev (XXXX-XX-XX) +------------------------- + +**Enhancement** + +* Add contributions type / category filters +* Add contributions manager +* Add contribution status + + 1.1.0 (2023-13-06) ------------------------- diff --git a/georiviere/contribution/admin.py b/georiviere/contribution/admin.py index 383d59e3..a1b3d9ca 100644 --- a/georiviere/contribution/admin.py +++ b/georiviere/contribution/admin.py @@ -2,9 +2,10 @@ from georiviere.contribution.models import ( SeverityType, LandingType, JamType, DiseaseType, DeadSpecies, InvasiveSpecies, HeritageSpecies, HeritageObservation, - FishSpecies, NaturePollution, TypePollution + FishSpecies, NaturePollution, TypePollution, ContributionStatus ) +admin.site.register(ContributionStatus, admin.ModelAdmin) admin.site.register(SeverityType, admin.ModelAdmin) admin.site.register(LandingType, admin.ModelAdmin) admin.site.register(JamType, admin.ModelAdmin) diff --git a/georiviere/contribution/filters.py b/georiviere/contribution/filters.py index affd7b5f..92de3afe 100644 --- a/georiviere/contribution/filters.py +++ b/georiviere/contribution/filters.py @@ -70,5 +70,5 @@ class ContributionFilterSet(WatershedFilterSet, ZoningFilterSet, MapEntityFilter class Meta(MapEntityFilterSet.Meta): model = Contribution fields = MapEntityFilterSet.Meta.fields + [ - "category_contribution", "type_contribution" + "category_contribution", "type_contribution", 'status_contribution', 'assigned_user' ] diff --git a/georiviere/contribution/fixtures/basic.json b/georiviere/contribution/fixtures/basic.json new file mode 100644 index 00000000..8fcee7df --- /dev/null +++ b/georiviere/contribution/fixtures/basic.json @@ -0,0 +1,38 @@ +[ +{ + "model": "contribution.contributionstatus", + "pk": 1, + "fields": { + "label": "Informé", + "date_insert": "2023-05-09T15:15:30.143Z", + "date_update": "2022-03-09T15:15:30.143Z" + } +}, +{ + "model": "contribution.contributionstatus", + "pk": 2, + "fields": { + "label": "En cours de traitement", + "date_insert": "2023-05-09T15:15:30.143Z", + "date_update": "2022-03-09T15:15:30.143Z" + } +}, +{ + "model": "contribution.contributionstatus", + "pk": 3, + "fields": { + "label": "Traité", + "date_insert": "2023-05-09T15:15:30.143Z", + "date_update": "2022-03-09T15:15:30.143Z" + } +}, +{ + "model": "contribution.contributionstatus", + "pk": 4, + "fields": { + "label": "Retour au contributeur", + "date_insert": "2023-05-09T15:15:30.143Z", + "date_update": "2022-03-09T15:15:30.143Z" + } +} +] diff --git a/georiviere/contribution/forms.py b/georiviere/contribution/forms.py index 597405d2..1fec349c 100644 --- a/georiviere/contribution/forms.py +++ b/georiviere/contribution/forms.py @@ -15,12 +15,15 @@ class ContributionForm(CommonForm): "severity", "published", "portal", - "email_author" + "email_author", + "assigned_user", + "status_contribution" ) ] class Meta(CommonForm): - fields = ["description", "severity", "published", "portal", "email_author", "geom"] + fields = ["description", "severity", "published", "portal", "email_author", "geom", "assigned_user", + "status_contribution"] model = Contribution def __init__(self, *args, **kwargs): diff --git a/georiviere/contribution/managers.py b/georiviere/contribution/managers.py new file mode 100644 index 00000000..f2485506 --- /dev/null +++ b/georiviere/contribution/managers.py @@ -0,0 +1,7 @@ +from django.contrib.gis.db import models + + +class SelectableUserManager(models.Manager): + + def get_queryset(self): + return super().get_queryset().filter(userprofile__isnull=False) diff --git a/georiviere/contribution/migrations/0004_auto_20230724_1502.py b/georiviere/contribution/migrations/0004_auto_20230724_1502.py new file mode 100644 index 00000000..0d2212a2 --- /dev/null +++ b/georiviere/contribution/migrations/0004_auto_20230724_1502.py @@ -0,0 +1,50 @@ +# Generated by Django 3.1.14 on 2023-07-24 15:02 + +from django.db import migrations, models +import django.db.models.deletion +import georiviere.contribution.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ('contribution', '0003_auto_20230601_0910'), + ] + + operations = [ + migrations.CreateModel( + name='ContributionStatus', + 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')), + ('label', models.CharField(max_length=128, verbose_name='Status')), + ], + options={ + 'verbose_name': 'Status', + 'verbose_name_plural': 'Status', + }, + ), + migrations.CreateModel( + name='SelectableUser', + fields=[ + ], + options={ + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('auth.user',), + ), + migrations.AddField( + model_name='contribution', + name='assigned_user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='contributions', to='contribution.selectableuser', verbose_name='Supervisor'), + ), + migrations.AddField( + model_name='contribution', + name='status_contribution', + field=models.ForeignKey(blank=True, default=georiviere.contribution.models.status_default, null=True, on_delete=django.db.models.deletion.PROTECT, to='contribution.contributionstatus', verbose_name='Status'), + ), + ] diff --git a/georiviere/contribution/models.py b/georiviere/contribution/models.py index 6a978d53..ec86d77f 100644 --- a/georiviere/contribution/models.py +++ b/georiviere/contribution/models.py @@ -1,4 +1,5 @@ from django.conf import settings +from django.contrib.auth.models import User from django.contrib.gis.db import models from django.utils.translation import gettext_lazy as _ @@ -8,6 +9,7 @@ from geotrek.common.utils import classproperty from geotrek.zoning.mixins import ZoningPropertiesMixin +from georiviere.contribution.managers import SelectableUserManager from georiviere.description.models import Status, Morphology, Usage from georiviere.river.models import Stream from georiviere.knowledge.models import Knowledge @@ -29,6 +31,33 @@ def __str__(self): return self.label +class ContributionStatus(TimeStampedModelMixin, models.Model): + label = models.CharField(verbose_name=_("Status"), max_length=128) + + class Meta: + verbose_name = _("Status") + verbose_name_plural = _("Status") + + def __str__(self): + return self.label + + +class SelectableUser(User): + + objects = SelectableUserManager() + + class Meta: + proxy = True + + +def status_default(): + """Set status to New by default""" + new_status_query = ContributionStatus.objects.filter(label="Informé") + if new_status_query: + return new_status_query.get().pk + return None + + class Contribution(TimeStampedModelMixin, WatershedPropertiesMixin, ZoningPropertiesMixin, AddPropertyBufferMixin, MapEntityMixin): """contribution model""" @@ -46,6 +75,22 @@ class Contribution(TimeStampedModelMixin, WatershedPropertiesMixin, ZoningProper portal = models.ForeignKey('portal.Portal', verbose_name=_("Portal"), blank=True, related_name='contributions', on_delete=models.PROTECT) + assigned_user = models.ForeignKey( + SelectableUser, + blank=True, + on_delete=models.PROTECT, + null=True, + verbose_name=_("Supervisor"), + related_name="contributions" + ) + status_contribution = models.ForeignKey( + "ContributionStatus", + on_delete=models.PROTECT, + null=True, + blank=True, + default=status_default, + verbose_name=_("Status"), + ) class Meta: verbose_name = _("Contribution") diff --git a/georiviere/contribution/templates/contribution/contribution_detail_attributes.html b/georiviere/contribution/templates/contribution/contribution_detail_attributes.html index 88e6fb1c..09ed6269 100644 --- a/georiviere/contribution/templates/contribution/contribution_detail_attributes.html +++ b/georiviere/contribution/templates/contribution/contribution_detail_attributes.html @@ -27,6 +27,14 @@ {{ object|verbose:"description" }} {{ object.description|linebreaks }} + + {{ object|verbose:"assigned_user" }} + {{ object.assigned_user|default:"" }} + + + {{ object|verbose:"status_contribution" }} + {{ object.status_contribution|default:"" }} + {% if object.potential_damage %} {{ object.potential_damage|verbose:"type" }} diff --git a/georiviere/contribution/tests/factories.py b/georiviere/contribution/tests/factories.py index 951ef6d0..efd86da0 100644 --- a/georiviere/contribution/tests/factories.py +++ b/georiviere/contribution/tests/factories.py @@ -5,6 +5,13 @@ from georiviere.portal.tests.factories import PortalFactory +class ContributionStatusFactory(django.DjangoModelFactory): + class Meta: + model = models.ContributionStatus + + label = Sequence(lambda n: f'Contribution status {n}') + + class ContributionFactory(PointFactory): class Meta: model = models.Contribution diff --git a/georiviere/contribution/tests/test_models.py b/georiviere/contribution/tests/test_models.py index 7cc72add..848fe089 100644 --- a/georiviere/contribution/tests/test_models.py +++ b/georiviere/contribution/tests/test_models.py @@ -5,13 +5,14 @@ ContributionLandscapeElementsFactory, SeverityTypeTypeFactory, LandingTypeFactory, JamTypeFactory, DiseaseTypeFactory, DeadSpeciesFactory, InvasiveSpeciesFactory, HeritageSpeciesFactory, HeritageObservationFactory, FishSpeciesFactory, NaturePollutionFactory, - TypePollutionFactory) + TypePollutionFactory, ContributionStatusFactory) class ContributionCategoriesTest(TestCase): """Test for Category Contribution model""" def test_contribution_str(self): + ContributionStatusFactory(label="Informé") contribution = ContributionFactory(email_author='mail.mail@mail') self.assertEqual(str(contribution), "mail.mail@mail") self.assertEqual(contribution.category, "No category") @@ -125,3 +126,11 @@ def test_naturepollution_str(self): def test_typepollution_str(self): type_pollution = TypePollutionFactory(label="Type pollution 1") self.assertEqual(str(type_pollution), "Type pollution 1") + + +class ContributionStatusTest(TestCase): + """Test for Status Contribution model""" + + def test_status_str(self): + nature_pollution = ContributionStatusFactory(label="Contribution status 1") + self.assertEqual(str(nature_pollution), "Contribution status 1") diff --git a/georiviere/contribution/tests/test_views.py b/georiviere/contribution/tests/test_views.py index 903fc5ee..a604d3bb 100644 --- a/georiviere/contribution/tests/test_views.py +++ b/georiviere/contribution/tests/test_views.py @@ -11,6 +11,7 @@ class ContributionViewTestCase(CommonRiverTest): def get_expected_json_attrs(self): return { 'id': self.obj.pk, + 'assigned_user': self.obj.assigned_user, 'name_author': self.obj.name_author, 'email_author': self.obj.email_author, 'description': self.obj.description, @@ -21,7 +22,8 @@ def get_expected_json_attrs(self): 'severity': self.obj.severity, 'geom': self.obj.geom.ewkt, 'portal': self.obj.portal.pk, - 'published': False + 'published': False, + 'status_contribution': self.obj.status_contribution } def get_good_data(self):