def user_detail(request, pk): user = request.user if str(pk) != str(user.pk): user = get_object_or_404(User, pk=pk) if request.method == 'POST': if request.user == user: if 'changeset' in request.session and request.POST.get( 'deactivate_changeset') == '1': request.session.pop('changeset', None) messages.success(request, _('You deactivated your current changeset.')) return redirect(request.path) if request.changeset.pk is None and ChangeSet.can_direct_edit( request): if request.POST.get('direct_editing') == '1': request.session['direct_editing'] = True messages.success(request, _('You activated direct editing.')) return redirect(request.path) elif request.POST.get('direct_editing') == '0': request.session.pop('direct_editing', None) messages.success(request, _('You deactivated direct editing.')) return redirect(request.path) ctx = { 'user': user, 'can_direct_edit': ChangeSet.can_direct_edit(request), 'recent_changesets': ChangeSet.objects.filter(author=user).order_by('-last_update')[:15], } if request.user_permissions.review_changesets: ctx.update({ 'can_review': True, 'reviewing_changesets': ChangeSet.objects.filter(assigned_to=user, state='review').order_by('-last_update'), 'to_review_changesets': ChangeSet.objects.filter( state__in=('proposed', 'reproposed'), ).order_by('-last_update'), 'all_recent_changesets': ChangeSet.objects.exclude( state='unproposed').order_by('-last_update')[:20], }) return render(request, 'editor/user.html', ctx)
def direct_editing(self, request, *args, **kwargs): # django-rest-framework doesn't automatically do this for logged out requests SessionAuthentication().enforce_csrf(request) if not ChangeSet.can_direct_edit(request): raise PermissionDenied(_('You don\'t have the permission to activate direct editing.')) changeset = ChangeSet.get_for_request(request) if changeset.pk is not None: raise PermissionDenied(_('You cannot activate direct editing if you have an active changeset.')) request.session['direct_editing'] = True return Response({ 'success': True, })
def with_ajax_check(request, *args, **kwargs): if not can_access_editor(request): raise PermissionDenied request.changeset = ChangeSet.get_for_request(request, select_related) ajax = request.is_ajax() or 'ajax' in request.GET if not ajax: request.META.pop('HTTP_IF_NONE_MATCH', None) response = func(request, *args, **kwargs) if ajax: if isinstance(response, HttpResponseRedirect): return render(request, 'editor/redirect.html', {'target': response['location']}) if not isinstance(response, HttpResponseNotModified): response.write( render(request, 'editor/fragment_nav.html', {}).content) response['Cache-Control'] = 'no-cache' patch_vary_headers(response, ('X-Requested-With', )) return response if isinstance(response, HttpResponseRedirect): return response response = render(request, 'editor/map.html', {'content': response.content.decode()}) response['Cache-Control'] = 'no-cache' patch_vary_headers(response, ('X-Requested-With', )) return response
def changeset_edit(request, pk): changeset = request.changeset if str(pk) != str(request.changeset.pk): changeset = get_object_or_404(ChangeSet.qs_for_request(request), pk=pk) with changeset.lock_to_edit(request) as changeset: if not changeset.can_edit(request): messages.error(request, _('You cannot edit this change set.')) return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) if request.method == 'POST': form = ChangeSetForm(instance=changeset, data=request.POST) if form.is_valid(): changeset = form.instance update = changeset.updates.create(user=request.user, title=changeset.title, description=changeset.description) changeset.last_update = update changeset.save() return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) else: form = ChangeSetForm(instance=changeset) return render(request, 'editor/changeset_edit.html', { 'changeset': changeset, 'form': form, })
def current(self, request, *args, **kwargs): changeset = ChangeSet.get_for_request(request) return Response({ 'direct_editing': changeset.direct_editing, 'changeset': changeset.serialize() if changeset.pk else None, })
def set_changeset_author_on_login(sender, user, request, **kwargs): try: changeset = request.changeset except AttributeError: changeset = ChangeSet.get_for_request(request, as_logged_out=True) if changeset.pk is not None: changeset.author = user changeset.save()
def etag_func(request, *args, **kwargs): try: changeset = request.changeset except AttributeError: changeset = ChangeSet.get_for_request(request) request.changeset = changeset return ( get_language() + ':' + changeset.raw_cache_key_by_changes + ':' + AccessPermission.cache_key_for_request(request, with_update=False) + ':' + str(request.user.pk or 0))
def user_detail(request, pk): user = request.user if str(pk) != str(user.pk): user = get_object_or_404(User, pk=pk) if request.method == 'POST': if request.user == user: if 'changeset' in request.session and request.POST.get('deactivate_changeset') == '1': request.session.pop('changeset', None) messages.success(request, _('You deactivated your current changeset.')) return redirect(request.path) if request.changeset.pk is None and ChangeSet.can_direct_edit(request): if request.POST.get('direct_editing') == '1': request.session['direct_editing'] = True messages.success(request, _('You activated direct editing.')) return redirect(request.path) elif request.POST.get('direct_editing') == '0': request.session.pop('direct_editing', None) messages.success(request, _('You deactivated direct editing.')) return redirect(request.path) ctx = { 'user': user, 'can_direct_edit': ChangeSet.can_direct_edit(request), 'recent_changesets': ChangeSet.qs_for_request(request).filter(author=user).order_by('-last_update')[:15], } if request.user_permissions.review_changesets: ctx.update({ 'can_review': True, 'reviewing_changesets': ChangeSet.objects.filter( assigned_to=user, state='review' ).order_by('-last_update'), 'to_review_changesets': ChangeSet.objects.filter( state__in=('proposed', 'reproposed'), ).order_by('-last_update'), 'all_recent_changesets': ChangeSet.objects.exclude(state='unproposed').order_by('-last_update')[:20], }) return render(request, 'editor/user.html', ctx)
def wrapped_func(self, request, *args, **kwargs): try: changeset = request.changeset except AttributeError: changeset = ChangeSet.get_for_request(request) request.changeset = changeset update_cache_key = request.changeset.raw_cache_key_without_changes update_cache_key_match = request.GET.get('update_cache_key') == update_cache_key return func(self, request, *args, update_cache_key=update_cache_key, update_cache_key_match=update_cache_key_match, **kwargs)
def etag_func(request, *args, **kwargs): try: changeset = request.changeset except AttributeError: changeset = ChangeSet.get_for_request(request) request.changeset = changeset return (get_language() + ':' + changeset.raw_cache_key_by_changes + ':' + AccessPermission.cache_key_for_request(request, with_update=False) + ':' + str(request.user.pk or 0) + ':' + str(int(request.user_permissions.can_access_base_mapdata)) + ':' + ','.join(str(i) for i in request.user_space_accesses) + ':' + str(int(request.user.is_superuser)))
def etag_func(request, *args, **kwargs): try: changeset = request.changeset except AttributeError: changeset = ChangeSet.get_for_request(request) request.changeset = changeset return (get_language() + ':' + changeset.raw_cache_key_by_changes + ':' + AccessPermission.cache_key_for_request( request, with_update=False) + ':' + str(request.user.pk or 0) + ':' + str(int(request.user_permissions.can_access_base_mapdata)) + ':' + ','.join(str(i) for i in request.user_space_accesses) + ':' + str(int(request.user.is_superuser)))
def wrapped(request, *args, api=False, **kwargs): if api and not api_hybrid: raise Exception('API call on a view without api_hybrid!') if not can_access_editor(request): raise PermissionDenied request.changeset = ChangeSet.get_for_request(request, select_related) if api: request.is_delete = request.method == 'DELETE' return call_api_hybrid_view_for_api(func, request, *args, **kwargs) ajax = request.is_ajax() or 'ajax' in request.GET if not ajax: request.META.pop('HTTP_IF_NONE_MATCH', None) if api_hybrid: response = call_api_hybrid_view_for_html(func, request, *args, **kwargs) else: response = func(request, *args, **kwargs) if ajax: if isinstance(response, HttpResponseRedirect): return render(request, 'editor/redirect.html', {'target': response['location']}) if not isinstance(response, HttpResponseNotModified): response.write( render(request, 'editor/fragment_nav.html', {}).content) if request.mobileclient: response.write( render(request, 'editor/fragment_mobileclientdata.html', {}).content) response['Cache-Control'] = 'no-cache' patch_vary_headers(response, ('X-Requested-With', )) return response if isinstance(response, HttpResponseRedirect): return response response = render(request, 'editor/map.html', {'content': response.content.decode()}) response['Cache-Control'] = 'no-cache' patch_vary_headers(response, ('X-Requested-With', )) return response
def wrapped(request, *args, api=False, **kwargs): if api and not api_hybrid: raise Exception('API call on a view without api_hybrid!') if not can_access_editor(request): raise PermissionDenied request.changeset = ChangeSet.get_for_request(request, select_related) if api: request.is_delete = request.method == 'DELETE' return call_api_hybrid_view_for_api(func, request, *args, **kwargs) ajax = request.is_ajax() or 'ajax' in request.GET if not ajax: request.META.pop('HTTP_IF_NONE_MATCH', None) if api_hybrid: response = call_api_hybrid_view_for_html(func, request, *args, **kwargs) else: response = func(request, *args, **kwargs) if ajax: if isinstance(response, HttpResponseRedirect): return render(request, 'editor/redirect.html', {'target': response['location']}) if not isinstance(response, HttpResponseNotModified): response.write(render(request, 'editor/fragment_nav.html', {}).content) if request.mobileclient: response.write(render(request, 'editor/fragment_mobileclientdata.html', {}).content) response['Cache-Control'] = 'no-cache' patch_vary_headers(response, ('X-Requested-With', )) return response if isinstance(response, HttpResponseRedirect): return response response = render(request, 'editor/map.html', {'content': response.content.decode()}) response['Cache-Control'] = 'no-cache' patch_vary_headers(response, ('X-Requested-With', )) return response
def changeset_detail(request, pk): changeset = request.changeset active = True if str(pk) != str(request.changeset.pk): active = False qs = ChangeSet.qs_for_request(request).select_related('last_update', 'last_state_update', 'last_change', 'author') changeset = get_object_or_404(qs, pk=pk) if not changeset.can_see(request): raise Http404 can_edit = changeset.can_edit(request) can_delete = changeset.can_delete(request) if request.method == 'POST': restore = request.POST.get('restore') if restore and restore.isdigit(): with changeset.lock_to_edit(request) as changeset: if changeset.can_edit(request): try: changed_object = changeset.changed_objects_set.get(pk=restore) except Exception: pass else: try: changed_object.restore() messages.success(request, _('Object has been successfully restored.')) except PermissionError: messages.error(request, _('You cannot restore this object, because it depends on ' 'a deleted object or it would violate a unique contraint.')) else: messages.error(request, _('You can not edit changes on this change set.')) return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) elif request.POST.get('activate') == '1': with changeset.lock_to_edit(request) as changeset: if changeset.can_activate(request): changeset.activate(request) messages.success(request, _('You activated this change set.')) else: messages.error(request, _('You can not activate this change set.')) return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) elif request.POST.get('propose') == '1': if not request.user.is_authenticated: messages.info(request, _('You need to log in to propose changes.')) return redirect(reverse('editor.login')+'?r='+request.path) with changeset.lock_to_edit(request) as changeset: if not changeset.title or not changeset.description: messages.warning(request, _('You need to add a title an a description to propose this change set.')) return redirect(reverse('editor.changesets.edit', kwargs={'pk': changeset.pk})) if changeset.can_propose(request): changeset.propose(request.user) messages.success(request, _('You proposed your changes.')) else: messages.error(request, _('You cannot propose this change set.')) return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) elif request.POST.get('unpropose') == '1': with changeset.lock_to_edit(request) as changeset: if changeset.can_unpropose(request): changeset.unpropose(request.user) messages.success(request, _('You unproposed your changes.')) else: messages.error(request, _('You cannot unpropose this change set.')) return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) elif request.POST.get('review') == '1': with changeset.lock_to_edit(request) as changeset: if changeset.can_start_review(request): changeset.start_review(request.user) messages.success(request, _('You are now reviewing these changes.')) else: messages.error(request, _('You cannot review these changes.')) return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) elif request.POST.get('reject') == '1': with changeset.lock_to_edit(request) as changeset: if not changeset.can_end_review(request): messages.error(request, _('You cannot reject these changes.')) return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) if request.POST.get('reject_confirm') == '1': form = RejectForm(data=request.POST) if form.is_valid(): changeset.reject(request.user, form.cleaned_data['comment'], form.cleaned_data['final']) messages.success(request, _('You rejected these changes.')) return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) else: form = RejectForm() return render(request, 'editor/changeset_reject.html', { 'changeset': changeset, 'form': form, }) elif request.POST.get('unreject') == '1': with changeset.lock_to_edit(request) as changeset: if not changeset.can_unreject(request): messages.error(request, _('You cannot unreject these changes.')) return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) changeset.unreject(request.user) messages.success(request, _('You unrejected these changes.')) return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) elif request.POST.get('apply') == '1': with changeset.lock_to_edit(request) as changeset: if not changeset.can_end_review(request): messages.error(request, _('You cannot accept and apply these changes.')) return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) if request.POST.get('apply_confirm') == '1': changeset.apply(request.user) messages.success(request, _('You accepted and applied these changes.')) return redirect(reverse('editor.changesets.detail', kwargs={'pk': changeset.pk})) return render(request, 'editor/changeset_apply.html', {}) elif request.POST.get('delete') == '1': with changeset.lock_to_edit(request) as changeset: if not changeset.can_delete(request): messages.error(request, _('You cannot delete this change set.')) if request.POST.get('delete_confirm') == '1': changeset.delete() messages.success(request, _('You deleted this change set.')) if request.user.is_authenticated: return redirect(reverse('editor.users.detail', kwargs={'pk': request.user.pk})) else: return redirect(reverse('editor.index')) return render(request, 'editor/delete.html', { 'model_title': ChangeSet._meta.verbose_name, 'obj_title': changeset.title, }) changeset.fill_changes_cache() ctx = { 'changeset': changeset, 'can_edit': can_edit, 'can_delete': can_delete, 'can_propose': changeset.can_propose(request), 'can_unpropose': changeset.can_unpropose(request), 'can_start_review': changeset.can_start_review(request), 'can_end_review': changeset.can_end_review(request), 'can_unreject': changeset.can_unreject(request), 'active': active, } cache_key = '%s:%s:%s:view_data' % (changeset.cache_key_by_changes, changeset.last_update_id, int(can_edit)) changed_objects_data = cache.get(cache_key) if changed_objects_data: ctx['changed_objects'] = changed_objects_data return render(request, 'editor/changeset.html', ctx) objects = changeset.get_objects() changed_objects_data = [] added_redirects = {} removed_redirects = {} for changed_object in changeset.changed_objects.get(LocationRedirect, {}).values(): if changed_object.is_created == changed_object.deleted: continue obj = objects[LocationRedirect][changed_object.obj_pk] redirect_list = (removed_redirects if changed_object.deleted else added_redirects) redirect_list.setdefault(obj.target_id, []).append(obj.slug) redirect_changed_objects = [] for pk in set(added_redirects.keys()) | set(removed_redirects.keys()): obj = objects[LocationSlug][pk] model = obj.__class__ try: changeset.changed_objects[model][pk] except KeyError: redirect_changed_objects.append((model, {pk: changeset.get_changed_object(obj)})) for model, changed_objects in chain(changeset.changed_objects.items(), redirect_changed_objects): if model == LocationRedirect: continue for pk, changed_object in changed_objects.items(): obj = objects[model][pk] obj_desc = format_lazy(_('{model} #{id}'), model=obj.__class__._meta.verbose_name, id=pk) if is_created_pk(pk): obj_still_exists = pk in changeset.created_objects.get(obj.__class__, ()) else: obj_still_exists = pk not in changeset.deleted_existing.get(obj.__class__, ()) edit_url = None if obj_still_exists and can_edit and not isinstance(obj, LocationRedirect): reverse_kwargs = {'pk': obj.pk} if hasattr(obj, 'space_id'): reverse_kwargs['space'] = obj.space_id elif hasattr(obj, 'level_id'): reverse_kwargs['level'] = obj.level_id try: edit_url = reverse('editor.' + obj.__class__._meta.default_related_name + '.edit', kwargs=reverse_kwargs) except NoReverseMatch: pass changes = [] missing_dependencies = changed_object.get_missing_dependencies() unique_collisions = changed_object.get_unique_collisions() changed_object_data = { 'model': obj.__class__, 'model_title': obj.__class__._meta.verbose_name, 'pk': changed_object.pk, 'desc': obj_desc, 'title': obj.title if getattr(obj, 'titles', None) else None, 'changes': changes, 'edit_url': edit_url, 'deleted': changed_object.deleted, 'missing_dependencies': missing_dependencies, 'unique_collisions': unique_collisions, 'order': (changed_object.deleted and changed_object.is_created, not changed_object.is_created), } changed_objects_data.append(changed_object_data) form_fields = changeset.wrap_model(type(obj)).EditorForm._meta.fields if changed_object.is_created: changes.append({ 'icon': 'plus', 'class': 'success', 'empty': True, 'title': _('created'), }) update_changes = [] for name, value in changed_object.updated_fields.items(): change_data = { 'icon': 'option-vertical', 'class': 'muted', } if name == 'geometry': change_data.update({ 'icon': 'map-marker', 'class': 'info', 'empty': True, 'title': _('created geometry') if changed_object.is_created else _('edited geometry'), 'order': (8,), }) elif name == 'data': change_data.update({ 'icon': 'signal', 'class': 'info', 'empty': True, 'title': _('created scan data') if changed_object.is_created else _('edited scan data'), 'order': (9,), }) else: if '__i18n__' in name: orig_name, i18n, lang = name.split('__') lang_info = get_language_info(lang) field = model._meta.get_field(orig_name) field_title = format_lazy(_('{field_name} ({lang})'), field_name=field.verbose_name, lang=lang_info['name_translated']) field_value = str(value) if field_value: getattr(obj, field.attname)[lang] = field_value else: getattr(obj, field.attname).pop(lang, None) change_data.update({ 'order': (4, tuple(code for code, title in settings.LANGUAGES).index(lang)), }) else: field = model._meta.get_field(name) field_title = field.verbose_name field_value = field.to_python(value) if field.related_model is not None: if issubclass(field.related_model, User): field_value = objects[field.related_model][field_value].username else: field_value = objects[field.related_model][field_value].title change_data.update({ 'missing_dependency': field.name in missing_dependencies, }) if name in unique_collisions: change_data.update({ 'unique_collision': field.name in unique_collisions, }) order = 5 if name == 'slug': order = 1 if name not in form_fields: order = 0 change_data.update({ 'order': (order, form_fields.index(name) if order else 1), }) if field_value == '' or field_value is None: change_data.update({ 'empty': True, 'title': format_lazy(_('remove {field_title}'), field_title=field_title), }) else: change_data.update({ 'title': field_title, 'value': field_value, }) update_changes.append(change_data) changes.extend(sorted(update_changes, key=itemgetter('order'))) for m2m_mode in ('m2m_added', 'm2m_removed'): m2m_list = getattr(changed_object, m2m_mode).items() for name, values in sorted(m2m_list, key=lambda nv: form_fields.index(nv[0])): field = model._meta.get_field(name) for value in values: changes.append({ 'icon': 'chevron-right' if m2m_mode == 'm2m_added' else 'chevron-left', 'class': 'info', 'title': field.verbose_name, 'value': objects[field.related_model][value].title, }) if isinstance(obj, LocationSlug): for slug in added_redirects.get(obj.pk, ()): changes.append({ 'icon': 'chevron-right', 'class': 'info', 'title': _('Redirect slugs'), 'value': slug, }) for slug in removed_redirects.get(obj.pk, ()): changes.append({ 'icon': 'chevron-left', 'class': 'info', 'title': _('Redirect slugs'), 'value': slug, }) if changed_object.deleted: changes.append({ 'icon': 'minus', 'class': 'danger', 'empty': True, 'title': _('deleted'), 'order': (9,), }) changed_objects_data = sorted(changed_objects_data, key=itemgetter('order')) cache.set(cache_key, changed_objects_data, 300) ctx['changed_objects'] = changed_objects_data return render(request, 'editor/changeset.html', ctx)
def current(self, request, *args, **kwargs): changeset = ChangeSet.get_for_request(request) return Response(changeset.serialize())
def get_queryset(self): return ChangeSet.qs_for_request(self.request).select_related('last_update', 'last_state_update', 'last_change')
def get_queryset(self): return ChangeSet.qs_for_request(self.request).select_related( 'last_update', 'last_state_update', 'last_change')
def current(self, request, *args, **kwargs): if not can_access_editor(request): return PermissionDenied changeset = ChangeSet.get_for_request(request) return Response(changeset.serialize())