direct editing

This commit is contained in:
Laura Klünder 2017-07-08 15:42:06 +02:00
parent df19daf501
commit 1caa730fc4
4 changed files with 67 additions and 9 deletions

View file

@ -9,7 +9,7 @@ from django.apps import apps
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from django.core.exceptions import FieldDoesNotExist from django.core.exceptions import FieldDoesNotExist
from django.db import models, transaction from django.db import connection, models, transaction
from django.db.models import Q from django.db.models import Q
from django.urls import reverse from django.urls import reverse
from django.utils.http import int_to_base36 from django.utils.http import int_to_base36
@ -69,6 +69,8 @@ class ChangeSet(models.Model):
self._request = None self._request = None
self._original_state = self.state self._original_state = self.state
self.direct_editing = False
""" """
Get Changesets for Request/Session/User Get Changesets for Request/Session/User
""" """
@ -111,6 +113,8 @@ class ChangeSet(models.Model):
changeset = ChangeSet() changeset = ChangeSet()
changeset._request = request changeset._request = request
if request.session.get('direct_editing', False) and ChangeSet.can_direct_edit(request):
changeset.direct_editing = True
if request.user.is_authenticated: if request.user.is_authenticated:
changeset.author = request.user changeset.author = request.user
@ -124,10 +128,15 @@ class ChangeSet(models.Model):
if isinstance(model, str): if isinstance(model, str):
model = apps.get_model('mapdata', model) model = apps.get_model('mapdata', model)
assert isinstance(model, type) and issubclass(model, models.Model) assert isinstance(model, type) and issubclass(model, models.Model)
if self.direct_editing:
model.EditorForm = ModelWrapper(self, model).EditorForm
return model
return ModelWrapper(self, model) return ModelWrapper(self, model)
def wrap_instance(self, instance): def wrap_instance(self, instance):
assert isinstance(instance, models.Model) assert isinstance(instance, models.Model)
if self.direct_editing:
return instance
return self.wrap_model(instance.__class__).create_wrapped_model_class()(self, instance) return self.wrap_model(instance.__class__).create_wrapped_model_class()(self, instance)
def relevant_changed_objects(self) -> typing.Iterable[ChangedObject]: def relevant_changed_objects(self) -> typing.Iterable[ChangedObject]:
@ -399,17 +408,24 @@ class ChangeSet(models.Model):
@contextmanager @contextmanager
def lock_to_edit(self, request=None): def lock_to_edit(self, request=None):
with transaction.atomic(): with transaction.atomic():
user = request.user if request is not None and request.user.is_authenticated else None
if self.pk is not None: if self.pk is not None:
changeset = ChangeSet.objects.select_for_update().get(pk=self.pk) changeset = ChangeSet.objects.select_for_update().get(pk=self.pk)
self._object_changed = False self._object_changed = False
yield changeset yield changeset
user = request.user if request is not None and request.user.is_authenticated else None
if self._object_changed: if self._object_changed:
update = changeset.updates.create(user=user, objects_changed=True) update = changeset.updates.create(user=user, objects_changed=True)
changeset.last_update = update changeset.last_update = update
changeset.last_change = update changeset.last_change = update
changeset.save() changeset.save()
elif self.direct_editing:
with MapUpdate.lock():
queries_before = len(connection.queries)
yield self
if any((q['sql'].startswith('UPDATE') or q['sql'].startswith('INSERT') or
q['sql'].startswith('DELETE')) for q in connection.queries[queries_before:]):
MapUpdate.objects.create(user=user, type='direct_edit')
else: else:
yield self yield self
@ -433,6 +449,11 @@ class ChangeSet(models.Model):
# todo implement permissions # todo implement permissions
return self.is_author(request) return self.is_author(request)
@classmethod
def can_direct_edit(self, request):
# todo implement permissions
return request.user.is_authenticated
def can_start_review(self, request): def can_start_review(self, request):
return self.can_review(request) and self.state in ('proposed', 'reproposed') return self.can_review(request) and self.state in ('proposed', 'reproposed')
@ -609,6 +630,8 @@ class ChangeSet(models.Model):
Get %d changed objects display text. Get %d changed objects display text.
""" """
if self.pk is None: if self.pk is None:
if self.direct_editing:
return _('Direct editing active')
return _('No objects changed') return _('No objects changed')
return (ungettext_lazy('%(num)d object changed', '%(num)d objects changed', 'num') % return (ungettext_lazy('%(num)d object changed', '%(num)d objects changed', 'num') %
{'num': self.changed_objects_count}) {'num': self.changed_objects_count})

View file

@ -1,7 +1,13 @@
{% load i18n %} {% load i18n %}
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li><a href="{{ request.changeset.get_absolute_url }}">{{ request.changeset.count_display }}</a></li> <li><a href="{{ request.changeset.get_absolute_url }}">
{% if request.changeset.direct_editing %}
<span class="text-warning">{{ request.changeset.count_display }}</span>
{% else %}
{{ request.changeset.count_display }}
{% endif %}
</a></li>
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<li class="logged_in_user"> <li class="logged_in_user">
<a href="{% url 'editor.users.detail' pk=request.user.pk %}">{{ request.user.username }}</a> <a href="{% url 'editor.users.detail' pk=request.user.pk %}">{{ request.user.username }}</a>

View file

@ -23,9 +23,26 @@
<button type="submit" class="btn btn-xs btn-default" name="deactivate_changeset" value="1">{% trans 'Deactivate change set' %}</button> <button type="submit" class="btn btn-xs btn-default" name="deactivate_changeset" value="1">{% trans 'Deactivate change set' %}</button>
</form> </form>
{% endwith %} {% endwith %}
{% elif request.changeset.direct_editing %}
<p>
{% trans 'Direct editing is activated.' %}<br>
{% trans 'Everything you do will be applied immediately.' %}
</p>
<form method="post" action="{{ request.path }}">
{% csrf_token %}
<button type="submit" class="btn btn-xs btn-warning" name="direct_editing" value="0">{% trans 'Deactivate direct editing' %}</button>
</form>
{% else %} {% else %}
<p>
{% trans 'You have currently no active change set.' %}<br> {% trans 'You have currently no active change set.' %}<br>
{% trans 'Just edit something to create one.' %} {% trans 'Just edit something to create one.' %}
</p>
{% if can_direct_edit %}
<form method="post" action="{{ request.path }}">
{% csrf_token %}
<button type="submit" class="btn btn-xs btn-warning" name="direct_editing" value="1">{% trans 'Activate direct editing' %}</button>
</form>
{% endif %}
{% endif %} {% endif %}
{% endif %} {% endif %}

View file

@ -14,13 +14,25 @@ def user_detail(request, pk):
user = get_object_or_404(User, pk=pk) user = get_object_or_404(User, pk=pk)
if request.method == 'POST': if request.method == 'POST':
if request.POST.get('deactivate_changeset') == '1' and request.user == user and 'changeset' in request.session: if request.user == user and 'changeset' in request.session:
if request.POST.get('deactivate_changeset') == '1':
request.session.pop('changeset', None) request.session.pop('changeset', None)
messages.success(request, _('You deactivated your current changeset.')) messages.success(request, _('You deactivated your current changeset.'))
return redirect(request.path) 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 = { ctx = {
'user': user, 'user': user,
'can_direct_edit': ChangeSet.can_direct_edit(request),
'recent_changesets': ChangeSet.objects.filter(author=user).order_by('-last_update')[:10], 'recent_changesets': ChangeSet.objects.filter(author=user).order_by('-last_update')[:10],
} }