Commit f17fb6e4 authored by Skia's avatar Skia
Browse files

Add lock handling in Wiki

parent 92f68f5b
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0014_remove_page_revision'),
operations = [
......@@ -5,7 +5,7 @@ from django.utils import timezone
from django.core import validators
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
from datetime import datetime
from datetime import datetime, timedelta
class User(AbstractBaseUser, PermissionsMixin):
......@@ -139,6 +139,18 @@ class GroupManagedObject(models.Model):
class Meta:
abstract = True
class LockError(Exception):
"""There was a lock error on the object"""
class AlreadyLocked(LockError):
"""The object is already locked"""
class NotLocked(LockError):
"""The object is not locked"""
class Page(GroupManagedObject, models.Model):
The page class to build a Wiki
......@@ -151,11 +163,11 @@ class Page(GroupManagedObject, models.Model):
query, but don't rely on it when playing with a Page object, use get_full_name() instead!
name = models.CharField(_('page name'), max_length=30, blank=False)
is_locked = models.BooleanField(_("page mutex"), default=False)
parent = models.ForeignKey('self', related_name="children", null=True, blank=True, on_delete=models.SET_NULL)
# Attention: this field may not be valid until you call save(). It's made for fast query, but don't rely on it when
# playing with a Page object, use get_full_name() instead!
full_name = models.CharField(_('page name'), max_length=255, blank=True)
lock_mutex = {}
class Meta:
......@@ -202,6 +214,11 @@ class Page(GroupManagedObject, models.Model):
return l
def save(self, *args, **kwargs):
Performs some needed actions before and after saving a page in database
if not self.is_locked():
raise NotLocked("The page is not locked and thus can not be saved")
# This reset the full_name just before saving to maintain a coherent field quicker for queries than the
# recursive method
......@@ -210,6 +227,53 @@ class Page(GroupManagedObject, models.Model):
for c in self.children.all():
super(Page, self).save(*args, **kwargs)
def is_locked(self):
Is True if the page is locked, False otherwise
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
if not in Page.lock_mutex.keys():
# print("Page mutex does not exists")
return False
if ([]['time']) > timedelta(seconds=5):
# print("Lock timed out")
return False
return True
def set_lock(self, user):
Sets a lock on the current page or raise an AlreadyLocked exception
if self.is_locked() and self.get_lock()['user'] != user:
raise AlreadyLocked("The page is already locked by someone else")
Page.lock_mutex[] = {'user': user,
# print("Locking page")
def set_lock_recursive(self, user):
Locks recursively all the child pages for editing properties
for p in self.children.all():
def unset_lock(self):
"""Always try to unlock, even if there is no lock"""
Page.lock_mutex.pop(, None)
# print("Unlocking page")
def get_lock(self):
Returns the page's mutex containing the time and the user in a dict
if self.is_locked():
return Page.lock_mutex[]
raise NotLocked("The page is not locked and thus can not return its mutex")
def get_absolute_url(self):
......@@ -252,4 +316,8 @@ class PageRev(models.Model):
def __str__(self):
return str(self.__dict__)
def save(self, *args, **kwargs):
super(PageRev, self).save(*args, **kwargs)
# Don't forget to unlock, otherwise, people will have to wait for the page's timeout
......@@ -5,7 +5,7 @@ from django.views.generic.edit import UpdateView
from django.contrib.auth.decorators import login_required, permission_required
from django.utils.decorators import method_decorator
from core.models import Page, PageRev
from core.models import Page, PageRev, LockError
from core.views.forms import PagePropForm
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin
......@@ -77,6 +77,10 @@ class PagePropView(CanEditPropMixin, UpdateView):
parent = Page.get_page_by_full_name(parent_name)
p = Page(name=name, parent=parent) = p
except LockError as e:
raise e
def get_context_data(self, **kwargs):
......@@ -98,6 +102,10 @@ class PageEditView(CanEditMixin, UpdateView):
rev = PageRev(author=request.user)
except LockError as e:
raise e
return None
......@@ -110,17 +118,13 @@ class PageEditView(CanEditMixin, UpdateView):
return context
def form_valid(self, form): = self.request.user =
# TODO : factor that, but first make some tests
rev = form.instance
new_rev = PageRev(title=rev.title,
) = self.request.user =
form.instance = new_rev
return super(PageEditView, self).form_valid(form)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment