Fix Page locking

This commit is contained in:
Skia 2016-11-05 13:37:30 +01:00
parent c0c8b295ba
commit 59f5917b8c
6 changed files with 56 additions and 24 deletions

View File

@ -167,15 +167,14 @@ Welcome to the wiki page!
r.save() r.save()
# Adding syntax help page # Adding syntax help page
p = Page(name='Aide_sur_la_syntaxe') p = Page(name='Aide_sur_la_syntaxe')
p.save() p.save(force_lock=True)
PageRev(page=p, title="Aide sur la syntaxe", author=skia, content=""" PageRev(page=p, title="Aide sur la syntaxe", author=skia, content="""
Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site. Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site.
""").save() """).save()
p = Page(name='Services') p = Page(name='Services')
p.save() p.save(force_lock=True)
p.set_lock(skia)
p.view_groups=[settings.SITH_GROUPS['public']['id']] p.view_groups=[settings.SITH_GROUPS['public']['id']]
p.save() p.save(force_lock=True)
PageRev(page=p, title="Services", author=skia, content=""" PageRev(page=p, title="Services", author=skia, content="""
| | | | | | | |
| :---: | :---: | :---: | | :---: | :---: | :---: |
@ -185,10 +184,9 @@ Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site.
""").save() """).save()
# Adding README # Adding README
p = Page(name='README') p = Page(name='README')
p.save() p.save(force_lock=True)
p.view_groups=[settings.SITH_GROUPS['public']['id']] p.view_groups=[settings.SITH_GROUPS['public']['id']]
p.set_lock(skia) p.save(force_lock=True)
p.save()
with open(os.path.join(root_path)+'/README.md', 'r') as rm: with open(os.path.join(root_path)+'/README.md', 'r') as rm:
PageRev(page=p, title="README", author=skia, content=rm.read()).save() PageRev(page=p, title="README", author=skia, content=rm.read()).save()

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
('core', '0004_user_godfathers'),
]
operations = [
migrations.AddField(
model_name='page',
name='lock_timeout',
field=models.DateTimeField(verbose_name='lock_timeout', null=True, blank=True, default=None),
),
migrations.AddField(
model_name='page',
name='lock_user',
field=models.ForeignKey(verbose_name='lock user', default=None, blank=True, to=settings.AUTH_USER_MODEL, null=True, related_name='locked_pages'),
),
]

View File

@ -630,7 +630,8 @@ class Page(models.Model):
default=settings.SITH_GROUPS['root']['id']) default=settings.SITH_GROUPS['root']['id'])
edit_groups = models.ManyToManyField(Group, related_name="editable_page", verbose_name=_("edit group"), blank=True) edit_groups = models.ManyToManyField(Group, related_name="editable_page", verbose_name=_("edit group"), blank=True)
view_groups = models.ManyToManyField(Group, related_name="viewable_page", verbose_name=_("view group"), blank=True) view_groups = models.ManyToManyField(Group, related_name="viewable_page", verbose_name=_("view group"), blank=True)
lock_mutex = {} lock_user = models.ForeignKey(User, related_name="locked_pages", verbose_name=_("lock user"), blank=True, null=True, default=None)
lock_timeout = models.DateTimeField(_('lock_timeout'), null=True, blank=True, default=None)
class Meta: class Meta:
unique_together = ('name', 'parent') unique_together = ('name', 'parent')
@ -679,7 +680,9 @@ class Page(models.Model):
""" """
Performs some needed actions before and after saving a page in database Performs some needed actions before and after saving a page in database
""" """
if not self.is_locked(): locked = kwargs.pop('force_lock', False)
if not locked: locked = self.is_locked()
if not locked:
raise NotLocked("The page is not locked and thus can not be saved") raise NotLocked("The page is not locked and thus can not be saved")
self.full_clean() self.full_clean()
# This reset the _full_name just before saving to maintain a coherent field quicker for queries than the # This reset the _full_name just before saving to maintain a coherent field quicker for queries than the
@ -697,23 +700,20 @@ class Page(models.Model):
This is where the timeout is handled, so a locked page for which the timeout is reach will be unlocked and this This is where the timeout is handled, so a locked page for which the timeout is reach will be unlocked and this
function will return False function will return False
""" """
if self.pk not in Page.lock_mutex.keys(): if self.lock_timeout and (timezone.now() - self.lock_timeout > timedelta(minutes=5)):
# print("Page mutex does not exists")
return False
if (timezone.now()-Page.lock_mutex[self.pk]['time']) > timedelta(minutes=5):
# print("Lock timed out") # print("Lock timed out")
self.unset_lock() self.unset_lock()
return False return self.lock_user and self.lock_timeout and (timezone.now() - self.lock_timeout < timedelta(minutes=5))
return True
def set_lock(self, user): def set_lock(self, user):
""" """
Sets a lock on the current page or raise an AlreadyLocked exception Sets a lock on the current page or raise an AlreadyLocked exception
""" """
if self.is_locked() and self.get_lock()['user'] != user: if self.is_locked() and self.get_lock() != user:
raise AlreadyLocked("The page is already locked by someone else") raise AlreadyLocked("The page is already locked by someone else")
Page.lock_mutex[self.pk] = {'user': user, self.lock_user = user
'time': timezone.now()} self.lock_timeout = timezone.now()
super(Page, self).save()
# print("Locking page") # print("Locking page")
def set_lock_recursive(self, user): def set_lock_recursive(self, user):
@ -726,16 +726,18 @@ class Page(models.Model):
def unset_lock(self): def unset_lock(self):
"""Always try to unlock, even if there is no lock""" """Always try to unlock, even if there is no lock"""
Page.lock_mutex.pop(self.pk, None) self.lock_user = None
self.lock_timeout = None
super(Page, self).save()
# print("Unlocking page") # print("Unlocking page")
def get_lock(self): def get_lock(self):
""" """
Returns the page's mutex containing the time and the user in a dict Returns the page's mutex containing the time and the user in a dict
""" """
if self.is_locked(): if self.lock_user:
return Page.lock_mutex[self.pk] return self.lock_user
raise NotLocked("The page is not locked and thus can not return its mutex") raise NotLocked("The page is not locked and thus can not return its user")
def get_absolute_url(self): def get_absolute_url(self):
""" """

View File

@ -37,6 +37,12 @@ class CanCreateMixin(View):
This view is made to protect any child view that would create an object, and thus, that can not be protected by any This view is made to protect any child view that would create an object, and thus, that can not be protected by any
of the following mixin of the following mixin
""" """
def dispatch(self, request, *arg, **kwargs):
res = super(CanCreateMixin, self).dispatch(request, *arg, **kwargs)
if not request.user.is_authenticated():
raise PermissionDenied
return res
def form_valid(self, form): def form_valid(self, form):
obj = form.instance obj = form.instance
if can_edit_prop(obj, self.request.user): if can_edit_prop(obj, self.request.user):

View File

@ -9,7 +9,7 @@ from django.forms import CheckboxSelectMultiple
from core.models import Page, PageRev, LockError from core.models import Page, PageRev, LockError
from core.views.forms import PagePropForm from core.views.forms import PagePropForm
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin
class PageListView(CanViewMixin, ListView): class PageListView(CanViewMixin, ListView):
model = Page model = Page
@ -59,7 +59,7 @@ class PageRevView(CanViewMixin, DetailView):
context['new_page'] = self.kwargs['page_name'] context['new_page'] = self.kwargs['page_name']
return context return context
class PageCreateView(CanEditPropMixin, CreateView): class PageCreateView(CanCreateMixin, CreateView):
model = Page model = Page
form_class = modelform_factory(Page, form_class = modelform_factory(Page,
fields = ['parent', 'name', 'owner_group', 'edit_groups', 'view_groups', ], fields = ['parent', 'name', 'owner_group', 'edit_groups', 'view_groups', ],

View File

@ -442,5 +442,6 @@ OLD_MYSQL_INFOS = {
try: try:
from .settings_custom import * from .settings_custom import *
print("Custom settings imported")
except: except:
print("Custom settings failed") print("Custom settings failed")