def post(self, request, slug, feature_type_slug): context = {} try: up_file = request.FILES['image_file'] except Exception: logger.exception('ImportFromImage.post') context['status'] = "error" context['message'] = "Erreur à l'import du fichier. " status = 400 try: data_geom_wkt = exif.get_image_geoloc_as_wkt(up_file, with_alt=False, ewkt=False) except Exception: logger.exception('ImportFromImage.post') context['status'] = "error" context['message'] = "Erreur lors de la lecture des données GPS. " status = 400 else: geom = self.get_geom(data_geom_wkt) context['geom'] = geom.wkt context['status'] = "success" status = 200 return JsonResponse(context, status=status)
def get(self, request, slug, action): project = self.get_object() user = request.user if action.lower() not in ['ajouter', 'annuler']: msg = "Erreur de syntaxe dans l'url d'abonnement. " logger.error(msg) messages.error(request, "Cette action est incorrecte") elif action.lower() == 'ajouter': obj, _created = Subscription.objects.get_or_create( project=project, ) obj.users.add(user) obj.save() messages.info( request, 'Vous êtes maintenant abonné aux notifications de ce projet. ') elif action.lower() == 'annuler': try: obj = Subscription.objects.get(project=project) obj.users.remove(user) obj.save() messages.info( request, 'Vous ne recevrez plus les notifications de ce projet. ') except Exception: logger.exception('SubscribingView.get') return redirect('geocontrib:project', slug=slug)
def set_auth_member(sender, instance, created, **kwargs): Authorization = apps.get_model(app_label='geocontrib', model_name="Authorization") UserLevelPermission = apps.get_model(app_label='geocontrib', model_name="UserLevelPermission") Project = apps.get_model(app_label='geocontrib', model_name="Project") if created: try: for project in Project.objects.all(): Authorization.objects.create( project=project, user=instance, level=UserLevelPermission.objects.get(rank=1)) except Exception: logger.exception('Trigger.set_auth_member') elif not instance.is_active: try: for project in Project.objects.all(): Authorization.objects.update_or_create( project=project, user=instance, defaults={ 'level': UserLevelPermission.objects.get(rank=0) }) except Exception: logger.exception('Trigger.set_auth_member')
def set_users_perms(sender, instance, created, **kwargs): # On ajoute la permission d'admin de projet au créateur if created: Authorization = apps.get_model(app_label='geocontrib', model_name="Authorization") UserLevelPermission = apps.get_model(app_label='geocontrib', model_name="UserLevelPermission") User = apps.get_model(app_label='geocontrib', model_name="User") try: Authorization.objects.create( project=instance, user=instance.creator, level=UserLevelPermission.objects.get(rank=4)) except Exception: logger.exception('Trigger.set_users_perms') try: for user in User.objects.filter(is_active=True).exclude( pk=instance.creator.pk): Authorization.objects.update_or_create( project=instance, user=user, defaults={ 'level': UserLevelPermission.objects.get(rank=1) }) except Exception: logger.exception('Trigger.set_users_perms')
def notify_or_stack_events(sender, instance, created, **kwargs): if created and instance.project_slug and settings.DEFAULT_SENDING_FREQUENCY != 'never': # On empile les evenements pour notifier les abonnés, en fonction de la fréquence d'envoi StackedEvent = apps.get_model(app_label='geocontrib', model_name="StackedEvent") stack, _ = StackedEvent.objects.get_or_create( sending_frequency=settings.DEFAULT_SENDING_FREQUENCY, state='pending', project_slug=instance.project_slug) stack.events.add(instance) stack.save() # On notifie les collaborateurs des messages nécessitant une action immédiate try: instance.ping_users() except Exception: logger.exception('ping_users@notify_or_stack_events')
def __init__(self, *args, **kwargs): feature_type = kwargs.pop('feature_type', None) feature = kwargs.pop('feature', None) super().__init__(*args, **kwargs) qs = Feature.objects.all() if feature_type: qs = qs.filter(feature_type=feature_type) if feature: qs = qs.exclude(feature_id=feature.feature_id) try: self.fields['feature_to'].queryset = qs self.fields[ 'feature_to'].label_from_instance = lambda obj: "{} ({} - {})".format( obj.title, obj.display_creator, obj.created_on.strftime("%d/%m/%Y %H:%M")) except Exception: logger.exception('No related features found')
def get_context_data(self, feature_id=None, **kwargs): self.object = self.get_object() context = super().get_context_data(**kwargs) try: request = self.request project = None title = None if any([isinstance(self.object, model) for model in [Project, FeatureType, Feature]]): title = self.object.title if isinstance(self.object, Project): project = self.object elif isinstance(self.object, FeatureType) or isinstance(self.object, Feature): project = self.object.project serialized_base_maps = BaseMapSerializer( BaseMap.objects.filter(project=project), many=True ) serialized_layers = LayerSerializer( Layer.objects.all(), many=True ) features = Feature.handy.availables(user=self.request.user, project=project) if feature_id: features = features.filter(feature_id=feature_id) serialized_features = FeatureDetailedSerializer( features, is_authenticated=request.user.is_authenticated, context={'request': request}, many=True ) context['serialized_features'] = serialized_features.data context['serialized_base_maps'] = serialized_base_maps.data context['serialized_layers'] = serialized_layers.data context['title'] = title except Exception: logger.exception('BaseMapContext error') return context
def post(self, request, slug, feature_type_slug): feature_type = self.get_object() try: up_file = request.FILES['json_file'].read() data = json.loads(up_file.decode('utf-8')) except Exception: logger.exception('ImportFromGeoJSON.post') messages.error(request, "Erreur à l'import du fichier. ") else: try: with transaction.atomic(): self.check_feature_type_slug(request, data, feature_type_slug) self.create_features(request, request.user, data, feature_type) except IntegrityError: messages.error( request, "Erreur lors de l'import d'un fichier GeoJSON. ") return redirect('geocontrib:feature_type_detail', slug=slug, feature_type_slug=feature_type_slug)
def post(self, request, slug, feature_type_slug): user = request.user feature_type = self.get_object() project = feature_type.project permissions = Authorization.all_permissions(user, project) feature_form = FeatureBaseForm(request.POST, feature_type=feature_type, user=user) extra = CustomField.objects.filter(feature_type=feature_type) extra_form = FeatureExtraForm(request.POST, extra=extra) linked_formset = self.LinkedFormset( request.POST or None, prefix='linked', form_kwargs={'feature_type': feature_type}, ) attachment_formset = self.AttachmentFormset(request.POST or None, request.FILES, prefix='attachment') all_forms = [ feature_form, extra_form, attachment_formset, linked_formset, ] forms_are_valid = all([ff.is_valid() for ff in all_forms]) if forms_are_valid: try: feature = feature_form.save(project=project, feature_type=feature_type, creator=user, extra=extra_form.cleaned_data) except Exception as err: logger.exception('FeatureCreate.post') messages.error( request, "Une erreur s'est produite lors de la création du signalement {title}: {err}" .format(title=feature_form.cleaned_data.get( 'title', 'N/A'), err=str(err))) else: # Traitement des signalements liés for data in linked_formset.cleaned_data: feature_link = data.pop('id', None) if feature_link: if not data.get('DELETE'): feature_link.relation_type = data.get( 'relation_type') feature_link.feature_to = data.get('feature_to') feature_link.save() if data.get('DELETE'): feature_link.delete() if not feature_link and not data.get('DELETE'): FeatureLink.objects.create( relation_type=data.get('relation_type'), feature_from=feature, feature_to=data.get('feature_to')) # Traitement des piéces jointes for data in attachment_formset.cleaned_data: attachment = data.pop('id', None) if attachment and data.get('DELETE'): attachment.delete() if attachment and not data.get('DELETE'): attachment.attachment_file = data.get( 'attachment_file') attachment.title = data.get('title') attachment.info = data.get('info') attachment.save() if not attachment and not data.get('DELETE'): Attachment.objects.create( attachment_file=data.get('attachment_file'), title=data.get('title'), info=data.get('info'), object_type='feature', project=project, feature_id=feature.feature_id, author=user, ) messages.info( request, "Le signalement {title} a bien été créé. ".format( title=feature.title, )) return redirect('geocontrib:feature_detail', slug=project.slug, feature_type_slug=feature_type.slug, feature_id=feature.feature_id) else: logger.error([ff.errors for ff in all_forms]) linked_formset = self.LinkedFormset( request.POST or None, prefix='linked', form_kwargs={'feature_type': feature_type}, ) attachment_formset = self.AttachmentFormset(request.POST or None, request.FILES, prefix='attachment') context = { **self.get_context_data(), **{ 'features': Feature.handy.availables(user, project).order_by('updated_on'), 'feature_type': feature_type, 'project': project, 'permissions': permissions, 'feature_form': feature_form, 'extra_form': extra_form, 'linked_formset': linked_formset, 'attachment_formset': attachment_formset, 'action': 'create', } } return render(request, 'geocontrib/feature/feature_edit.html', context)
def ping_users(self, *args, **kwargs): """ Les différents cas d'envoi de notifications sont : - Les modérateurs d’un projet sont notifiés des signalements dont le statut devient "pending" (en attente de publication). Cela n'a de sens que pour les projets qui sont modérés. - L'auteur d'un signalement est notifié des changements de statut du signalement, des modifications du signalement et de l’ajout de commentaires (si l'auteur n'est pas lui-même à l'origine de ces évènements). - Un utilisateur abonné à un projet est notifié de tout évènement (dont il n'est pas à l'origine) sur ce projet. """ event_initiator = self.user if self.object_type == 'feature': Feature = apps.get_model(app_label='geocontrib', model_name='Feature') feature = Feature.objects.get(feature_id=self.feature_id) project = feature.project if project.moderation: # On notifie les modérateurs du projet si l'evenement concerne # Un demande de publication d'un signalement feature_status = self.data.get('feature_status', {}) status_has_changed = feature_status.get('has_changed', False) new_status = feature_status.get('new_status', 'draft') if status_has_changed and new_status == 'pending': Authorization = apps.get_model(app_label='geocontrib', model_name='Authorization') UserLevelPermission = apps.get_model( app_label='geocontrib', model_name='UserLevelPermission') moderateur_rank = UserLevelPermission.objects.get( user_type_id=MODERATOR).rank moderators__emails = Authorization.objects.filter( project=project, level__rank__gte=moderateur_rank ).exclude( user= event_initiator # On exclue l'initiateur de l'evenement. ).values_list('user__email', flat=True) context = { 'feature': feature, 'event_initiator': event_initiator, 'application_name': settings.APPLICATION_NAME, 'application_abstract': settings.APPLICATION_ABSTRACT, } logger.debug(moderators__emails) try: notif_moderators_pending_features( emails=moderators__emails, context=context) except Exception: logger.exception('Event.ping_users') # On notifie l'auteur du signalement si l'evenement concerne # la publication de son signalement if status_has_changed and new_status == 'published': if event_initiator != feature.creator: context = {'feature': feature, 'event': self} try: notif_creator_published_feature(emails=[ feature.creator.email, ], context=context) except Exception: logger.exception( 'Event.ping_users.notif_creator_published_feature' )
def post(self, request, slug, feature_type_slug, feature_id): feature = self.get_object() project = feature.project user = request.user form = CommentForm(request.POST, request.FILES) linked_features = FeatureLink.objects.filter( feature_from=feature.feature_id) serialized_link = FeatureLinkSerializer(linked_features, many=True) if form.is_valid(): try: comment = Comment.objects.create( feature_id=feature.feature_id, feature_type_slug=feature.feature_type.slug, author=user, project=project, comment=form.cleaned_data.get('comment')) up_file = form.cleaned_data.get('attachment_file') title = form.cleaned_data.get('title') info = form.cleaned_data.get('info') if comment and up_file and title: Attachment.objects.create(feature_id=feature.feature_id, author=user, project=project, comment=comment, attachment_file=up_file, title=title, info=info, object_type='comment') except Exception as err: logger.exception('CommentCreate.post') messages.error( request, "Erreur à l'ajout du commentaire: {err}".format(err=err)) else: # Un evenement est ajouter lors de la creation d'un commentaire # au niveau des trigger. messages.info(request, "Ajout du commentaire confirmé") return redirect('geocontrib:feature_detail', slug=slug, feature_type_slug=feature_type_slug, feature_id=feature_id) else: logger.error(form.errors) events = Event.objects.filter( feature_id=feature.feature_id).order_by('created_on') serialized_events = EventSerializer(events, many=True) context = { **self.get_context_data(), **{ 'feature': feature, 'feature_data': feature.custom_fields_as_list, 'feature_types': FeatureType.objects.filter(project=project), 'feature_type': feature.feature_type, 'linked_features': serialized_link.data, 'project': project, 'permissions': Authorization.all_permissions(user, project, feature), 'comments': Comment.objects.filter(project=project, feature_id=feature.feature_id), 'attachments': Attachment.objects.filter(project=project, feature_id=feature.feature_id, object_type='feature'), 'events': serialized_events.data, 'comment_form': form, } } return render(request, 'geocontrib/feature/feature_detail.html', context)