diff --git a/CHANGELOG.md b/CHANGELOG.md index b4070e9c..4edf8b76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## Unreleased + +## [1.1.1] - 2020-10-29 + +### Changed +- increase thickness of segments of features and reduced the transparency of dotted features + +### Fixed +- The creator is correctly displayed in the features and the feature types +- In the basemaps form, the display of a very long layer name is now responsive +- A browser title (tab) is now displayed for all pages +- Projects with limited access are no longer accessible to everyone +- The features are now filtered when search on the map +- The search in the list of features now stay in the same page +- The Georchestra plugin now keeps user rights defined in GeoContrib +- Draft features are now hidden on the section "Last features" +- Empty comments are now blocked + ## [1.1.0] - 2020-08-28 ### Changed @@ -15,7 +33,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [1.1.0-rc1] - 2020-08-19 ### Added -- geOrchestra plugin: automatically associate role to users when the user database is synchronised (see +- geOrchestra plugin: automatically associate role to users when the user database is synchronised (see [geOrchestra plugin](plugin_georchestra/README.md)) - add a function to search for places and addresses in the interactive maps. This new feature comes with new settings: `GEOCODER_PROVIDERS` and `SELECTED_GEOCODER` @@ -29,10 +47,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - change the label of the feature type field `title` in the front-end form (Titre -> Nom) - change the data model for basemaps: one basemap may contain several layers. Layers are declared by GéoContrib admin users. Basemaps are created by project admin users by selecting layers, ordering them and setting the opacity -of each of them. End users may switch from one basemap to another in the interactive maps. One user can change -the order of the layers and their opacity in the interactive maps. These personnal adjustments are stored in the +of each of them. End users may switch from one basemap to another in the interactive maps. One user can change +the order of the layers and their opacity in the interactive maps. These personnal adjustments are stored in the web browser of the user (local storage) and do not alter the basemaps as seen by other users. -- change default value for `LOGO_PATH` setting: Neogeo Technologie logo. This new image is located in the media +- change default value for `LOGO_PATH` setting: Neogeo Technologie logo. This new image is located in the media directory. - change all visible names in front-end and docs from `Geocontrib` to `GéoContrib` - set the leaflet background container to white diff --git a/api/serializers.py b/api/serializers.py index aacb1ecd..35d7bc49 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -80,7 +80,7 @@ class UserSerializer(serializers.ModelSerializer): full_name = serializers.SerializerMethodField() def get_full_name(self, obj): - return obj.get_full_name() + return obj.get_full_name() or obj.username class Meta: model = User @@ -99,7 +99,7 @@ class CommentSerializer(serializers.ModelSerializer): created_on = serializers.DateTimeField(format="%d/%m/%Y", read_only=True) - author = UserSerializer(read_only=True) + display_author = serializers.ReadOnlyField() related_feature = serializers.SerializerMethodField() @@ -122,7 +122,7 @@ class Meta: fields = ( 'created_on', 'comment', - 'author', + 'display_author', 'related_feature', ) @@ -267,7 +267,7 @@ def get_feature_to(self, obj): 'title': str(feature.title), 'feature_url': feature.get_view_url(), 'created_on': feature.created_on.strftime("%d/%m/%Y %H:%M"), - 'creator': feature.creator.display_creator, + 'creator': feature.display_creator, } except Exception: logger.exception('No related feature found') @@ -285,7 +285,7 @@ class EventSerializer(serializers.ModelSerializer): created_on = serializers.DateTimeField(format="%d/%m/%Y %H:%M", read_only=True) - user = UserSerializer(read_only=True) + display_user = serializers.ReadOnlyField() related_comment = serializers.SerializerMethodField() @@ -344,7 +344,7 @@ class Meta: 'feature_id', 'comment_id', 'attachment_id', - 'user', + 'display_user', 'related_comment', 'related_feature', 'project_url', diff --git a/docs/users.md b/docs/users.md index 8862affc..2d29fe96 100644 --- a/docs/users.md +++ b/docs/users.md @@ -9,6 +9,7 @@ Autorisations attribuables par projet : Autorisations indépendantes des projets : * Super utilisateur * Gestionnaire métier +* Statut équipe ## Autorisations liées aux projets @@ -89,3 +90,9 @@ Un gestionnaire métier peut : Le créateur d'un nouveau projet en devient automatiquement administrateur projet du projet en question. + +### Statut équipe + +Un utilisateur avec le statut équipe peut se connecter à l'interface administrateur. +Il accède aux fonctionnalités de l'interface selon les permissions qui lui ont été accordées. + diff --git a/geocontrib/context_processors.py b/geocontrib/context_processors.py index f6f0ace7..42687b65 100644 --- a/geocontrib/context_processors.py +++ b/geocontrib/context_processors.py @@ -1,7 +1,8 @@ +import logging + from django.conf import settings + from geocontrib.models import Authorization -import json -import logging logger = logging.getLogger(__name__) diff --git a/geocontrib/emails.py b/geocontrib/emails.py index 194af091..ba12a36d 100644 --- a/geocontrib/emails.py +++ b/geocontrib/emails.py @@ -76,7 +76,7 @@ def notif_creator_published_feature(emails, context): context['url_feature'] = urljoin(CURRENT_SITE_DOMAIN, feature.get_view_url()) - subject = "[Collab:{project_slug}] Confirmation de la publication de l'un de vos signalement.".format( + subject = "[Collab:{project_slug}] Confirmation de la publication de l'un de vos signalements.".format( project_slug=feature.project.slug ) diff --git a/geocontrib/forms.py b/geocontrib/forms.py index 8ce0131e..e898446b 100644 --- a/geocontrib/forms.py +++ b/geocontrib/forms.py @@ -114,7 +114,7 @@ def clean(self): continue name = form.cleaned_data.get('name') if name in names: - raise forms.ValidationError("Les champs supplémentaires ne peuvent avoir des nom similaires.") + raise forms.ValidationError("Les champs supplémentaires ne peuvent avoir des noms similaires.") names.append(name) @@ -149,7 +149,7 @@ class CommentForm(forms.ModelForm): attachment_file = forms.FileField(label="Fichier joint", required=False) info = forms.CharField( - label="Information additonelle au fichier joint", required=False, widget=forms.Textarea()) + label="Information additionnelle au fichier joint", required=False, widget=forms.Textarea()) class Meta: model = Comment @@ -205,7 +205,7 @@ class AuthorizationForm(forms.ModelForm): username = forms.CharField(label="Nom d'utilisateur") - email = forms.EmailField(label="Adresse email") + email = forms.EmailField(label="Adresse email", required=False) level = forms.ModelChoiceField( label="Niveau d'autorisation", @@ -414,7 +414,7 @@ def __init__(self, *args, **kwargs): self.fields['feature_to'].choices = tuple( (feat.feature_id, "{} ({} - {})".format( - feat.title, feat.creator.display_creator, feat.created_on.strftime("%d/%m/%Y %H:%M"))) for feat in qs + feat.title, feat.display_creator, feat.created_on.strftime("%d/%m/%Y %H:%M"))) for feat in qs ) except Exception: diff --git a/geocontrib/models.py b/geocontrib/models.py index 27a9c651..1d1e2052 100644 --- a/geocontrib/models.py +++ b/geocontrib/models.py @@ -156,7 +156,7 @@ def all_permissions(cls, user, project, feature=None): user_rank = cls.get_rank(user, project) - if user_rank >= project_rank_min or project_rank_min < 2: + if user_rank >= project_rank_min or project_rank_min == 0: user_perms['can_view_project'] = True user_perms['can_view_feature'] = True user_perms['can_view_feature_type'] = True @@ -592,6 +592,13 @@ def save(self, *args, **kwargs): self.created_on = timezone.now() super().save(*args, **kwargs) + @property + def display_author(self): + res = "Utilisateur supprimé" + if self.author: + res = self.author.get_full_name() or self.author.username + return res + class Attachment(AnnotationAbstract): @@ -684,6 +691,13 @@ def save(self, *args, **kwargs): self.created_on = timezone.now() super().save(*args, **kwargs) + @property + def display_user(self): + res = "Utilisateur supprimé" + if self.user: + res = self.user.get_full_name() or self.user.username + return res + @property def contextualize_action(self): evt = 'Aucun evenement' diff --git a/geocontrib/static/geocontrib/css/base.css b/geocontrib/static/geocontrib/css/base.css index c1e351af..40924439 100644 --- a/geocontrib/static/geocontrib/css/base.css +++ b/geocontrib/static/geocontrib/css/base.css @@ -64,6 +64,15 @@ main { color: #9f3a38; } +/* Fix semantic ui overflow when is too long */ +.layer-item .form div.text { + width: 100% +} + +.ui.selection.dropdown .menu>.item { + word-break: break-all; +} + /* Needs this unfortunatly, because semantic overrides the background-color */ #form-layers .blue-background-class { background-color: rgb(205, 229, 245); diff --git a/geocontrib/static/geocontrib/js/map-util.js b/geocontrib/static/geocontrib/js/map-util.js index 44fa1289..c8307fdd 100644 --- a/geocontrib/static/geocontrib/js/map-util.js +++ b/geocontrib/static/geocontrib/js/map-util.js @@ -99,37 +99,50 @@ const mapUtil = { this.addLayers(layers); }, - addFeatures: function (features) { + addFeatures: function (features, filter) { featureGroup = new L.FeatureGroup(); features.forEach((feature) => { - const geomJSON = turf.flip(feature.geometry); - const popupContent = this._createContentPopup(feature); + let filters = []; - if (geomJSON.type === 'Point') { - L.circleMarker(geomJSON.coordinates, { - color: feature.properties.feature_type.color, - radius: 4, - fillOpacity: 0.3, - weight: 1, - }) - .bindPopup(popupContent) - .addTo(featureGroup); - } else if (geomJSON.type === 'LineString') { - L.polyline(geomJSON.coordinates, { - color: feature.properties.feature_type.color, - weight: 1.5, - }) - .bindPopup(popupContent) - .addTo(featureGroup); - } else if (geomJSON.type === 'Polygon') { - L.polygon(geomJSON.coordinates, { - color: feature.properties.feature_type.color, - weight: 1.5, - fillOpacity: 0.3, - }) - .bindPopup(popupContent) - .addTo(featureGroup); + if (filter) { + const typeCheck = filter.featureType && feature.properties.feature_type.slug === filter.featureType; + const statusCheck = filter.featureStatus && feature.properties.status.value === filter.featureStatus; + const titleCheck = filter.featureTitle && feature.properties.title.includes(filter.featureTitle); + filters = [typeCheck, statusCheck, titleCheck]; + } + + if (!filter || !Object.values(filter).some(val => val) || Object.values(filter).some(val => val) && filters.length && filters.every(val => val !== false)) { + + const geomJSON = turf.flip(feature.geometry); + + const popupContent = this._createContentPopup(feature); + + if (geomJSON.type === 'Point') { + L.circleMarker(geomJSON.coordinates, { + color: feature.properties.feature_type.color, + radius: 4, + fillOpacity: 0.5, + weight: 3, + }) + .bindPopup(popupContent) + .addTo(featureGroup); + } else if (geomJSON.type === 'LineString') { + L.polyline(geomJSON.coordinates, { + color: feature.properties.feature_type.color, + weight: 3, + }) + .bindPopup(popupContent) + .addTo(featureGroup); + } else if (geomJSON.type === 'Polygon') { + L.polygon(geomJSON.coordinates, { + color: feature.properties.feature_type.color, + weight: 3, + fillOpacity: 0.5, + }) + .bindPopup(popupContent) + .addTo(featureGroup); + } } }); map.addLayer(featureGroup); diff --git a/geocontrib/templates/geocontrib/base.html b/geocontrib/templates/geocontrib/base.html index d8b91972..68a4f3a5 100644 --- a/geocontrib/templates/geocontrib/base.html +++ b/geocontrib/templates/geocontrib/base.html @@ -42,6 +42,9 @@ + + + @@ -52,7 +55,7 @@
-