Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
AE
Sith
Commits
f17fb6e4
Commit
f17fb6e4
authored
Dec 02, 2015
by
Skia
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add lock handling in Wiki
parent
92f68f5b
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
98 additions
and
8 deletions
+98
-8
core/migrations/0015_remove_page_is_locked.py
core/migrations/0015_remove_page_is_locked.py
+18
-0
core/models.py
core/models.py
+70
-2
core/views/page.py
core/views/page.py
+10
-6
No files found.
core/migrations/0015_remove_page_is_locked.py
0 → 100644
View file @
f17fb6e4
# -*- 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
=
[
migrations
.
RemoveField
(
model_name
=
'page'
,
name
=
'is_locked'
,
),
]
core/models.py
View file @
f17fb6e4
...
...
@@ -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"""
pass
class
AlreadyLocked
(
LockError
):
"""The object is already locked"""
pass
class
NotLocked
(
LockError
):
"""The object is not locked"""
pass
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"
)
self
.
full_clean
()
# 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
():
c
.
save
()
super
(
Page
,
self
).
save
(
*
args
,
**
kwargs
)
self
.
unset_lock
()
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
self
.
pk
not
in
Page
.
lock_mutex
.
keys
():
# print("Page mutex does not exists")
return
False
if
(
timezone
.
now
()
-
Page
.
lock_mutex
[
self
.
pk
][
'time'
])
>
timedelta
(
seconds
=
5
):
# print("Lock timed out")
self
.
unset_lock
()
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
[
self
.
pk
]
=
{
'user'
:
user
,
'time'
:
timezone
.
now
()}
# print("Locking page")
def
set_lock_recursive
(
self
,
user
):
"""
Locks recursively all the child pages for editing properties
"""
for
p
in
self
.
children
.
all
():
p
.
set_lock_recursive
(
user
)
self
.
set_lock
(
user
)
def
unset_lock
(
self
):
"""Always try to unlock, even if there is no lock"""
Page
.
lock_mutex
.
pop
(
self
.
pk
,
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
[
self
.
pk
]
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
self
.
page
.
unset_lock
()
core/views/page.py
View file @
f17fb6e4
...
...
@@ -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
)
self
.
page
=
p
try
:
self
.
page
.
set_lock_recursive
(
self
.
request
.
user
)
except
LockError
as
e
:
raise
e
return
self
.
page
def
get_context_data
(
self
,
**
kwargs
):
...
...
@@ -98,6 +102,10 @@ class PageEditView(CanEditMixin, UpdateView):
rev
=
PageRev
(
author
=
request
.
user
)
rev
.
save
()
self
.
page
.
revisions
.
add
(
rev
)
try
:
self
.
page
.
set_lock
(
self
.
request
.
user
)
except
LockError
as
e
:
raise
e
return
self
.
page
.
revisions
.
all
().
last
()
return
None
...
...
@@ -110,17 +118,13 @@ class PageEditView(CanEditMixin, UpdateView):
return
context
def
form_valid
(
self
,
form
):
form
.
instance
.
author
=
self
.
request
.
user
form
.
instance
.
page
=
self
.
page
# TODO : factor that, but first make some tests
rev
=
form
.
instance
new_rev
=
PageRev
(
title
=
rev
.
title
,
content
=
rev
.
content
,
)
new_rev
.
author
=
self
.
request
.
user
new_rev
.
page
=
self
.
page
print
(
form
.
instance
)
new_rev
.
save
()
form
.
instance
=
new_rev
print
(
form
.
instance
)
return
super
(
PageEditView
,
self
).
form_valid
(
form
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment