Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
AE UTBM
Sith
Commits
a14d940d
Commit
a14d940d
authored
Feb 05, 2016
by
Skia
Browse files
Some refactoring and misc improvements
parent
ed080b76
Changes
16
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
a14d940d
...
...
@@ -19,9 +19,33 @@ There is a Doxyfile at the root of the project, meaning that if you have Doxygen
generate a complete HTML documentation that will be available in the
*./doc/html/*
folder.
### Dependencies:
*
Django 1.8
*
Pillow
See requirements.txt
The development is done with sqlite, but it is advised to set a more robust DBMS for production (Postgresql for example)
### Misc about development
#### Controlling the rights
When you need to protect an object, there are three levels:
*
Editing the object properties
*
Editing the object various values
*
Viewing the object
Now you have many solutions in your model:
*
You can define a
`is_owned_by(self, user)`
, a
`can_be_edited_by(self, user)`
, and/or a
`can_be_viewed_by(self, user)`
method, each returning True is the user passed can edit/view the object, False otherwise.
This allows you to make complex request when the group solution is not powerful enough.
It's useful too when you want to define class-wide permissions, e.g. the club members, that are viewable only for
Subscribers.
*
You can add an
`owner_group`
field, as a ForeignKey to Group. Second is an
`edit_groups`
field, as a ManyToMany to
Group, and third is a
`view_groups`
, same as for edit.
Finally, when building a class based view, which is highly advised, you just have to inherit it from CanEditPropMixin,
CanEditMixin, or CanViewMixin, which are located in core.views. Your view will then be protected using either the
appropriate group fields, or the right method to check user permissions.
club/migrations/0002_auto_20160202_1345.py
View file @
a14d940d
...
...
@@ -14,12 +14,12 @@ class Migration(migrations.Migration):
operations
=
[
migrations
.
AddField
(
model_name
=
'club'
,
name
=
'edit_group'
,
name
=
'edit_group
s
'
,
field
=
models
.
ManyToManyField
(
to
=
'core.Group'
,
blank
=
True
,
related_name
=
'editable_club'
),
),
migrations
.
AddField
(
model_name
=
'club'
,
name
=
'view_group'
,
name
=
'view_group
s
'
,
field
=
models
.
ManyToManyField
(
to
=
'core.Group'
,
blank
=
True
,
related_name
=
'viewable_club'
),
),
]
club/models.py
View file @
a14d940d
...
...
@@ -6,6 +6,7 @@ from django.core.exceptions import ValidationError
from
django.core.urlresolvers
import
reverse
from
core.models
import
User
,
Group
from
subscription.models
import
Subscriber
# Create your models here.
...
...
@@ -31,8 +32,8 @@ class Club(models.Model):
# email = models.EmailField(_('email address'), unique=True) # This should, and will be generated automatically
owner_group
=
models
.
ForeignKey
(
Group
,
related_name
=
"owned_club"
,
default
=
settings
.
AE_GROUPS
[
'root'
][
'id'
])
edit_group
=
models
.
ManyToManyField
(
Group
,
related_name
=
"editable_club"
,
blank
=
True
)
view_group
=
models
.
ManyToManyField
(
Group
,
related_name
=
"viewable_club"
,
blank
=
True
)
edit_group
s
=
models
.
ManyToManyField
(
Group
,
related_name
=
"editable_club"
,
blank
=
True
)
view_group
s
=
models
.
ManyToManyField
(
Group
,
related_name
=
"viewable_club"
,
blank
=
True
)
def
check_loop
(
self
):
"""Raise a validation error when a loop is found within the parent list"""
...
...
@@ -53,6 +54,38 @@ class Club(models.Model):
def
get_absolute_url
(
self
):
return
reverse
(
'club:club_view'
,
kwargs
=
{
'club_id'
:
self
.
id
})
def
is_owned_by
(
self
,
user
):
"""
Method to see if that object can be super edited by the given user
"""
if
user
.
groups
.
filter
(
name
=
settings
.
AE_GROUPS
[
'board'
][
'name'
]).
exists
():
return
True
return
False
def
can_be_edited_by
(
self
,
user
):
"""
Method to see if that object can be edited by the given user
"""
ms
=
self
.
get_membership_for
(
user
)
if
ms
is
not
None
and
ms
.
role
>=
7
:
return
True
return
False
def
can_be_viewed_by
(
self
,
user
):
"""
Method to see if that object can be seen by the given user
"""
sub
=
Subscriber
.
objects
.
filter
(
pk
=
user
.
pk
).
first
()
if
sub
is
None
:
return
False
return
sub
.
is_subscribed
()
def
get_membership_for
(
self
,
user
):
"""
Returns the current membership the given user
"""
return
self
.
members
.
filter
(
user
=
user
.
id
).
filter
(
end_date
=
None
).
first
()
class
Membership
(
models
.
Model
):
"""
The Membership class makes the connection between User and Clubs
...
...
club/templates/club/club_detail.jinja
View file @
a14d940d
...
...
@@ -3,17 +3,16 @@
{%
block
content
%}
<h3>
Club
</h3>
<p><a
href=
"
{{
url
(
'club:club_list'
)
}}
"
>
Back to list
</a></p>
{%
if
user.
can_edit
(
club
)
%}
{%
if
can_edit
(
club
,
user
)
%}
<p><a
href=
"
{{
url
(
'club:club_edit'
,
club_id
=
club.pk
)
}}
"
>
Edit
</a></p>
<p><a
href=
"
{{
url
(
'club:club_members'
,
club_id
=
club.pk
)
}}
"
>
Edit members
</a></p>
{%
endif
%}
{%
if
user.is_owner
(
club
)
or
user.membership.
filter
(
end_date
=
None
)
.
filter
(
club
=
club.id
)
.
first
()
is
not
none
%}
{%
if
can_edit_prop
(
club
,
user
)
%}
<p><a
href=
"
{{
url
(
'club:club_prop'
,
club_id
=
club.pk
)
}}
"
>
Prop
</a>
TODO FIXME: this code sucks and is just a test!
We need something really easy to manage the views rights regarding the subscribing status and the membership of
someone!
</p>
{%
endif
%}
{%
if
can_view
(
club
,
user
)
%}
<p><a
href=
"
{{
url
(
'club:club_members'
,
club_id
=
club.pk
)
}}
"
>
Members
</a></p>
{%
endif
%}
<h3>
{{
club.name
}}
</h3>
<p>
{{
club.address
}}
</p>
<ul>
...
...
club/urls.py
View file @
a14d940d
...
...
@@ -6,7 +6,7 @@ urlpatterns = [
url
(
r
'^$'
,
ClubListView
.
as_view
(),
name
=
'club_list'
),
url
(
r
'^(?P<club_id>[0-9]+)/$'
,
ClubView
.
as_view
(),
name
=
'club_view'
),
url
(
r
'^(?P<club_id>[0-9]+)/edit$'
,
ClubEditView
.
as_view
(),
name
=
'club_edit'
),
url
(
r
'^(?P<club_id>[0-9]+)/members$'
,
Club
Edit
MembersView
.
as_view
(),
name
=
'club_members'
),
url
(
r
'^(?P<club_id>[0-9]+)/members$'
,
ClubMembersView
.
as_view
(),
name
=
'club_members'
),
url
(
r
'^(?P<club_id>[0-9]+)/prop$'
,
ClubEditPropView
.
as_view
(),
name
=
'club_prop'
),
#url(r'^(?P<club_id>[0-9]+)/tools$', ClubToolsView.as_view(), name='club_tools'),
...
...
club/views.py
View file @
a14d940d
...
...
@@ -3,10 +3,12 @@ from django.shortcuts import render
from
django.views.generic
import
ListView
,
DetailView
from
django.views.generic.edit
import
UpdateView
,
CreateView
from
django.forms
import
CheckboxSelectMultiple
from
django.core.exceptions
import
ValidationError
from
core.views
import
CanViewMixin
,
CanEditMixin
,
CanEditPropMixin
from
club.models
import
Club
,
Membership
from
subscription.views
import
SubscriberMixin
class
ClubListView
(
CanViewMixin
,
ListView
):
model
=
Club
...
...
@@ -31,23 +33,31 @@ class ClubMemberForm(forms.ModelForm):
fields
=
[
'user'
,
'role'
]
def
clean
(
self
):
print
(
self
.
__dict__
)
# TODO: see how to get access to request.user! We need some right validation somewhere!
return
super
(
ClubMemberForm
,
self
).
clean
()
ret
=
super
(
ClubMemberForm
,
self
).
clean
()
ms
=
self
.
instance
.
club
.
get_membership_for
(
self
.
_user
)
if
ms
is
not
None
and
ms
.
role
>=
self
.
cleaned_data
[
'role'
]:
return
ret
raise
ValidationError
(
"You do not have the permission to do that"
)
class
Club
Edit
MembersView
(
Can
Edit
Mixin
,
UpdateView
):
class
ClubMembersView
(
Can
View
Mixin
,
UpdateView
):
model
=
Club
pk_url_kwarg
=
"club_id"
form_class
=
ClubMemberForm
template_name
=
'club/club_members.jinja'
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
ClubMembersView
,
self
).
__init__
(
*
args
,
**
kwargs
)
# TODO FIXME: error forbidden when adding new member to club, because self.object changes to the Membership object
# somewhere!!!
def
get_form
(
self
):
form
=
super
(
Club
Edit
MembersView
,
self
).
get_form
()
form
=
super
(
ClubMembersView
,
self
).
get_form
()
if
'user'
in
form
.
data
and
form
.
data
.
get
(
'user'
)
!=
''
:
# Load an existing membership if possible
form
.
instance
=
Membership
.
objects
.
filter
(
club
=
self
.
object
).
filter
(
user
=
form
.
data
.
get
(
'user'
)).
filter
(
end_date
=
None
).
first
()
if
form
.
instance
is
None
:
# Instanciate a new membership
form
.
instance
=
Membership
(
club
=
self
.
object
,
user
=
self
.
request
.
user
)
form
.
initial
=
{
'user'
:
self
.
request
.
user
}
form
.
_user
=
self
.
request
.
user
return
form
class
ClubEditPropView
(
CanEditPropMixin
,
UpdateView
):
...
...
core/fixtures/pages.json
View file @
a14d940d
[{
"pk"
:
1
,
"model"
:
"core.page"
,
"fields"
:
{
"full_name"
:
"guy2"
,
"owner_group"
:
1
,
"parent"
:
null
,
"edit_group"
:
[],
"name"
:
"guy2"
,
"view_group"
:
[]}},
{
"pk"
:
2
,
"model"
:
"core.page"
,
"fields"
:
{
"full_name"
:
"guy2/bibou"
,
"owner_group"
:
1
,
"parent"
:
1
,
"edit_group"
:
[],
"name"
:
"bibou"
,
"view_group"
:
[]}},
{
"pk"
:
3
,
"model"
:
"core.page"
,
"fields"
:
{
"full_name"
:
"guy2/bibou/troll"
,
"owner_group"
:
1
,
"parent"
:
2
,
"edit_group"
:
[],
"name"
:
"troll"
,
"view_group"
:
[]}},
{
"pk"
:
4
,
"model"
:
"core.page"
,
"fields"
:
{
"full_name"
:
"guy"
,
"owner_group"
:
1
,
"parent"
:
null
,
"edit_group"
:
[
1
],
"name"
:
"guy"
,
"view_group"
:
[
1
]}},
{
"pk"
:
5
,
"model"
:
"core.page"
,
"fields"
:
{
"full_name"
:
"bibou"
,
"owner_group"
:
3
,
"parent"
:
null
,
"edit_group"
:
[
1
],
"name"
:
"bibou"
,
"view_group"
:
[]}},
{
"pk"
:
6
,
"model"
:
"core.page"
,
"fields"
:
{
"full_name"
:
"guy2/guy"
,
"owner_group"
:
1
,
"parent"
:
1
,
"edit_group"
:
[],
"name"
:
"guy"
,
"view_group"
:
[]}}]
\ No newline at end of file
[{
"pk"
:
1
,
"model"
:
"core.page"
,
"fields"
:
{
"full_name"
:
"guy2"
,
"owner_group"
:
1
,
"parent"
:
null
,
"edit_groups"
:
[],
"name"
:
"guy2"
,
"view_groups"
:
[]}},
{
"pk"
:
2
,
"model"
:
"core.page"
,
"fields"
:
{
"full_name"
:
"guy2/bibou"
,
"owner_group"
:
1
,
"parent"
:
1
,
"edit_group"
:
[],
"name"
:
"bibou"
,
"view_group"
:
[]}},
{
"pk"
:
3
,
"model"
:
"core.page"
,
"fields"
:
{
"full_name"
:
"guy2/bibou/troll"
,
"owner_group"
:
1
,
"parent"
:
2
,
"edit_group"
:
[],
"name"
:
"troll"
,
"view_group"
:
[]}},
{
"pk"
:
4
,
"model"
:
"core.page"
,
"fields"
:
{
"full_name"
:
"guy"
,
"owner_group"
:
1
,
"parent"
:
null
,
"edit_group"
:
[
1
],
"name"
:
"guy"
,
"view_group"
:
[
1
]}},
{
"pk"
:
5
,
"model"
:
"core.page"
,
"fields"
:
{
"full_name"
:
"bibou"
,
"owner_group"
:
3
,
"parent"
:
null
,
"edit_group"
:
[
1
],
"name"
:
"bibou"
,
"view_group"
:
[]}},
{
"pk"
:
6
,
"model"
:
"core.page"
,
"fields"
:
{
"full_name"
:
"guy2/guy"
,
"owner_group"
:
1
,
"parent"
:
1
,
"edit_group"
:
[],
"name"
:
"guy"
,
"view_group"
:
[]}}]
\ No newline at end of file
core/management/commands/setup.py
View file @
a14d940d
...
...
@@ -16,9 +16,10 @@ class Command(BaseCommand):
parser
.
add_argument
(
'--prod'
,
action
=
"store_true"
)
def
handle
(
self
,
*
args
,
**
options
):
root_path
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
))))
try
:
os
.
unlink
(
os
.
path
.
join
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
))))
,
'db.sqlite3'
))
os
.
mkdir
(
os
.
path
.
join
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
))))
)
+
'/data'
)
os
.
unlink
(
os
.
path
.
join
(
root_path
,
'db.sqlite3'
))
os
.
mkdir
(
os
.
path
.
join
(
root_path
)
+
'/data'
)
except
Exception
as
e
:
print
(
e
)
call_command
(
'migrate'
)
...
...
@@ -37,37 +38,41 @@ class Command(BaseCommand):
# Here we add a lot of test datas, that are not necessary for the Sith, but that provide a basic development environment
if
not
options
[
'prod'
]:
print
(
"Dev mode, adding some test data"
)
# Adding user Skia
s
=
User
(
username
=
'skia'
,
last_name
=
"Kia"
,
first_name
=
"S'"
,
email
=
"skia@git.an"
,
date_of_birth
=
"1942-06-12"
,
is_superuser
=
True
,
is_staff
=
True
)
date_of_birth
=
"1942-06-12"
)
s
.
set_password
(
"plop"
)
s
.
save
()
# Adding user Guy
u
=
User
(
username
=
'guy'
,
last_name
=
"Carlier"
,
first_name
=
"Guy"
,
email
=
"guy@git.an"
,
date_of_birth
=
"1942-06-12"
,
is_superuser
=
False
,
is_staff
=
False
)
u
.
set_password
(
"plop"
)
u
.
save
()
# Adding syntax help page
p
=
Page
(
name
=
'Aide_sur_la_syntaxe'
)
p
.
set_lock
(
s
)
p
.
save
()
PageRev
(
page
=
p
,
title
=
"Aide sur la syntaxe"
,
author
=
s
,
content
=
"""
Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site.
"""
).
save
()
# Accounting test values:
Customer
(
user
=
s
,
account_id
=
"6568j"
).
save
()
p
=
ProductType
(
name
=
"Bières bouteilles"
)
# Adding README
p
=
Page
(
name
=
'README'
)
p
.
set_lock
(
s
)
p
.
save
()
Product
(
name
=
"Barbar"
,
code
=
"BARB"
,
product_type
=
p
,
purchase_price
=
"1.50"
,
selling_price
=
"1.7"
,
special_selling_price
=
"1.6"
).
save
()
GeneralJournal
(
start_date
=
"2015-06-12"
,
name
=
"A15"
).
save
()
p
.
view_groups
=
[
settings
.
AE_GROUPS
[
'public'
][
'id'
]]
p
.
set_lock
(
s
)
p
.
save
()
with
open
(
os
.
path
.
join
(
root_path
)
+
'/README.md'
,
'r'
)
as
rm
:
PageRev
(
page
=
p
,
title
=
"REAMDE"
,
author
=
s
,
content
=
rm
.
read
()).
save
()
# Subscription
Subscription
(
member
=
Subscriber
.
objects
.
filter
(
pk
=
s
.
pk
).
first
(),
subscription_type
=
list
(
settings
.
AE_SUBSCRIPTIONS
.
keys
())[
0
],
payment_method
=
settings
.
AE_PAYMENT_METHOD
[
0
]).
save
()
# Clubs
Club
(
name
=
"Bibo'UT"
,
unix_name
=
"bibout"
,
address
=
"46 de la Boustifaille"
,
parent
=
ae
).
save
()
guyut
=
Club
(
name
=
"Guy'UT"
,
unix_name
=
"guyut"
,
...
...
@@ -77,3 +82,12 @@ Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site.
address
=
"Woenzel"
,
parent
=
guyut
).
save
()
Club
(
name
=
"BdF"
,
unix_name
=
"bdf"
,
address
=
"Guyéuéyuéyuyé"
).
save
()
# Accounting test values:
Customer
(
user
=
s
,
account_id
=
"6568j"
).
save
()
p
=
ProductType
(
name
=
"Bières bouteilles"
)
p
.
save
()
Product
(
name
=
"Barbar"
,
code
=
"BARB"
,
product_type
=
p
,
purchase_price
=
"1.50"
,
selling_price
=
"1.7"
,
special_selling_price
=
"1.6"
).
save
()
GeneralJournal
(
start_date
=
"2015-06-12"
,
name
=
"A15"
).
save
()
core/migrations/0001_initial.py
View file @
a14d940d
...
...
@@ -54,10 +54,10 @@ class Migration(migrations.Migration):
(
'id'
,
models
.
AutoField
(
serialize
=
False
,
auto_created
=
True
,
primary_key
=
True
,
verbose_name
=
'ID'
)),
(
'name'
,
models
.
CharField
(
max_length
=
30
,
verbose_name
=
'page name'
)),
(
'_full_name'
,
models
.
CharField
(
max_length
=
255
,
verbose_name
=
'page name'
,
blank
=
True
)),
(
'edit_group'
,
models
.
ManyToManyField
(
to
=
'core.Group'
,
related_name
=
'editable_page'
,
blank
=
True
)),
(
'edit_group
s
'
,
models
.
ManyToManyField
(
to
=
'core.Group'
,
related_name
=
'editable_page'
,
blank
=
True
)),
(
'owner_group'
,
models
.
ForeignKey
(
to
=
'core.Group'
,
related_name
=
'owned_page'
,
default
=
1
)),
(
'parent'
,
models
.
ForeignKey
(
to
=
'core.Page'
,
on_delete
=
django
.
db
.
models
.
deletion
.
SET_NULL
,
null
=
True
,
related_name
=
'children'
,
blank
=
True
)),
(
'view_group'
,
models
.
ManyToManyField
(
to
=
'core.Group'
,
related_name
=
'viewable_page'
,
blank
=
True
)),
(
'view_group
s
'
,
models
.
ManyToManyField
(
to
=
'core.Group'
,
related_name
=
'viewable_page'
,
blank
=
True
)),
],
options
=
{
'permissions'
:
((
'change_prop_page'
,
"Can change the page's properties (groups, ...)"
),
(
'view_page'
,
'Can view the page'
)),
...
...
@@ -79,7 +79,7 @@ class Migration(migrations.Migration):
),
migrations
.
AddField
(
model_name
=
'user'
,
name
=
'edit_group'
,
name
=
'edit_group
s
'
,
field
=
models
.
ManyToManyField
(
to
=
'core.Group'
,
related_name
=
'editable_user'
,
blank
=
True
),
),
migrations
.
AddField
(
...
...
@@ -99,7 +99,7 @@ class Migration(migrations.Migration):
),
migrations
.
AddField
(
model_name
=
'user'
,
name
=
'view_group'
,
name
=
'view_group
s
'
,
field
=
models
.
ManyToManyField
(
to
=
'core.Group'
,
related_name
=
'viewable_user'
,
blank
=
True
),
),
migrations
.
AlterUniqueTogether
(
...
...
core/models.py
View file @
a14d940d
...
...
@@ -65,8 +65,8 @@ class User(AbstractBaseUser, PermissionsMixin):
date_joined
=
models
.
DateField
(
_
(
'date joined'
),
auto_now_add
=
True
)
owner_group
=
models
.
ForeignKey
(
Group
,
related_name
=
"owned_user"
,
default
=
settings
.
AE_GROUPS
[
'root'
][
'id'
])
edit_group
=
models
.
ManyToManyField
(
Group
,
related_name
=
"editable_user"
,
blank
=
True
)
view_group
=
models
.
ManyToManyField
(
Group
,
related_name
=
"viewable_user"
,
blank
=
True
)
edit_group
s
=
models
.
ManyToManyField
(
Group
,
related_name
=
"editable_user"
,
blank
=
True
)
view_group
s
=
models
.
ManyToManyField
(
Group
,
related_name
=
"viewable_user"
,
blank
=
True
)
objects
=
UserManager
()
...
...
@@ -159,6 +159,8 @@ class User(AbstractBaseUser, PermissionsMixin):
self
.
has_perm
(
obj
.
__class__
.
__module__
.
split
(
'.'
)[
0
]
+
".change_prop_"
+
obj
.
__class__
.
__name__
.
lower
())
or
self
.
groups
.
filter
(
id
=
settings
.
AE_GROUPS
[
'root'
][
'id'
]).
exists
()):
return
True
if
hasattr
(
obj
,
"is_owned_by"
)
and
obj
.
is_owned_by
(
self
):
return
True
return
False
def
can_edit
(
self
,
obj
):
...
...
@@ -167,12 +169,14 @@ class User(AbstractBaseUser, PermissionsMixin):
"""
if
self
.
is_owner
(
obj
):
return
True
if
hasattr
(
obj
,
"edit_group"
):
for
g
in
obj
.
edit_group
.
all
():
if
hasattr
(
obj
,
"edit_group
s
"
):
for
g
in
obj
.
edit_group
s
.
all
():
if
self
.
groups
.
filter
(
name
=
g
.
name
).
exists
():
return
True
if
isinstance
(
obj
,
User
)
and
obj
==
self
:
return
True
if
hasattr
(
obj
,
"can_be_edited_by"
)
and
obj
.
can_be_edited_by
(
self
):
return
True
if
self
.
has_perm
(
obj
.
__class__
.
__module__
.
split
(
'.'
)[
0
]
+
".change_"
+
obj
.
__class__
.
__name__
.
lower
()):
return
True
return
False
...
...
@@ -183,10 +187,12 @@ class User(AbstractBaseUser, PermissionsMixin):
"""
if
self
.
can_edit
(
obj
):
return
True
if
hasattr
(
obj
,
"view_group"
):
for
g
in
obj
.
view_group
.
all
():
if
hasattr
(
obj
,
"view_group
s
"
):
for
g
in
obj
.
view_group
s
.
all
():
if
self
.
groups
.
filter
(
name
=
g
.
name
).
exists
():
return
True
if
hasattr
(
obj
,
"can_be_viewed_by"
)
and
obj
.
can_be_viewed_by
(
self
):
return
True
if
self
.
has_perm
(
obj
.
__class__
.
__module__
.
split
(
'.'
)[
0
]
+
".view_"
+
obj
.
__class__
.
__name__
.
lower
()):
return
True
return
False
...
...
@@ -202,7 +208,7 @@ class AnonymousUser(AuthAnonymousUser):
return
False
def
can_view
(
self
,
obj
):
if
obj
.
view_group
.
filter
(
pk
=
settings
.
AE_GROUPS
[
'public'
][
'id'
]).
exists
():
if
obj
.
view_group
s
.
filter
(
pk
=
settings
.
AE_GROUPS
[
'public'
][
'id'
]).
exists
():
return
True
return
False
...
...
@@ -236,8 +242,8 @@ class Page(models.Model):
_full_name
=
models
.
CharField
(
_
(
'page name'
),
max_length
=
255
,
blank
=
True
)
owner_group
=
models
.
ForeignKey
(
Group
,
related_name
=
"owned_page"
,
default
=
settings
.
AE_GROUPS
[
'root'
][
'id'
])
edit_group
=
models
.
ManyToManyField
(
Group
,
related_name
=
"editable_page"
,
blank
=
True
)
view_group
=
models
.
ManyToManyField
(
Group
,
related_name
=
"viewable_page"
,
blank
=
True
)
edit_group
s
=
models
.
ManyToManyField
(
Group
,
related_name
=
"editable_page"
,
blank
=
True
)
view_group
s
=
models
.
ManyToManyField
(
Group
,
related_name
=
"viewable_page"
,
blank
=
True
)
lock_mutex
=
{}
...
...
@@ -397,10 +403,10 @@ class PageRev(models.Model):
def
__getattribute__
(
self
,
attr
):
if
attr
==
"owner_group"
:
return
self
.
page
.
owner_group
elif
attr
==
"edit_group"
:
return
self
.
page
.
edit_group
elif
attr
==
"view_group"
:
return
self
.
page
.
view_group
elif
attr
==
"edit_group
s
"
:
return
self
.
page
.
edit_group
s
elif
attr
==
"view_group
s
"
:
return
self
.
page
.
view_group
s
elif
attr
==
"unset_lock"
:
return
self
.
page
.
unset_lock
else
:
...
...
core/views/__init__.py
View file @
a14d940d
...
...
@@ -12,6 +12,20 @@ def forbidden(request):
def
not_found
(
request
):
return
render
(
request
,
"core/404.jinja"
)
def
can_edit_prop
(
obj
,
user
):
if
obj
is
None
or
user
.
is_owner
(
obj
):
return
True
return
False
def
can_edit
(
obj
,
user
):
if
obj
is
None
or
user
.
can_edit
(
obj
):
return
True
return
can_edit_prop
(
obj
,
user
)
def
can_view
(
obj
,
user
):
if
obj
is
None
or
user
.
can_view
(
obj
):
return
True
return
can_edit
(
obj
,
user
)
class
CanEditPropMixin
(
View
):
"""
...
...
@@ -22,8 +36,11 @@ class CanEditPropMixin(View):
"""
def
dispatch
(
self
,
request
,
*
arg
,
**
kwargs
):
res
=
super
(
CanEditPropMixin
,
self
).
dispatch
(
request
,
*
arg
,
**
kwargs
)
if
((
hasattr
(
self
,
'object'
)
and
(
self
.
object
is
None
or
self
.
request
.
user
.
is_owner
(
self
.
object
)))
or
(
hasattr
(
self
,
'object_list'
)
and
(
self
.
object_list
is
None
or
self
.
object_list
is
[]
or
self
.
request
.
user
.
is_owner
(
self
.
object_list
[
0
])))):
if
hasattr
(
self
,
'object'
):
obj
=
self
.
object
elif
hasattr
(
self
,
'object_list'
):
obj
=
self
.
object_list
[
0
]
if
self
.
object_list
else
None
if
can_edit_prop
(
obj
,
self
.
request
.
user
):
return
res
try
:
# Always unlock when 403
self
.
object
.
unset_lock
()
...
...
@@ -32,35 +49,38 @@ class CanEditPropMixin(View):
class
CanEditMixin
(
View
):
"""
This view makes exactly the same this as its direct parent, but checks the group on the edit_group field of the
This view makes exactly the same this as its direct parent, but checks the group on the edit_group
s
field of the
object
"""
def
dispatch
(
self
,
request
,
*
arg
,
**
kwargs
):
# TODO: WIP: fix permissions with exceptions!
res
=
super
(
CanEditMixin
,
self
).
dispatch
(
request
,
*
arg
,
**
kwargs
)
if
((
hasattr
(
self
,
'object'
)
and
(
self
.
object
is
None
or
self
.
request
.
user
.
can_edit
(
self
.
object
)))
or
(
hasattr
(
self
,
'object_list'
)
and
(
self
.
object_list
is
None
or
self
.
object_list
is
[]
or
self
.
request
.
user
.
can_edit
(
self
.
object_list
[
0
])))):
if
hasattr
(
self
,
'object'
):
obj
=
self
.
object
elif
hasattr
(
self
,
'object_list'
):
obj
=
self
.
object_list
[
0
]
if
self
.
object_list
else
None
if
can_edit
(
obj
,
self
.
request
.
user
):
return
res
try
:
# Always unlock when 403
self
.
object
.
unset_lock
()
except
:
pass
print
(
"CanEditMixin 403"
)
raise
PermissionDenied
class
CanViewMixin
(
View
):
"""
This view still makes exactly the same this as its direct parent, but checks the group on the view_group field of
This view still makes exactly the same this as its direct parent, but checks the group on the view_group
s
field of
the object
"""
def
dispatch
(
self
,
request
,
*
arg
,
**
kwargs
):
res
=
super
(
CanViewMixin
,
self
).
dispatch
(
request
,
*
arg
,
**
kwargs
)
if
((
hasattr
(
self
,
'object'
)
and
(
self
.
object
is
None
or
self
.
request
.
user
.
can_view
(
self
.
object
)))
or
(
hasattr
(
self
,
'object_list'
)
and
(
self
.
object_list
is
None
or
self
.
object_list
is
[]
or
self
.
request
.
user
.
can_view
(
self
.
object_list
[
0
])))):
if
hasattr
(
self
,
'object'
):
obj
=
self
.
object
elif
hasattr
(
self
,
'object_list'
):
obj
=
self
.
object_list
[
0
]
if
self
.
object_list
else
None
if
can_view
(
obj
,
self
.
request
.
user
):
return
res
try
:
# Always unlock when 403
self
.
object
.
unset_lock
()
except
:
pass
print
(
"CanViewMixin 403"
)
raise
PermissionDenied
from
.user
import
*
...
...
core/views/forms.py
View file @
a14d940d
...
...
@@ -27,21 +27,21 @@ class UserPropForm(forms.ModelForm):
required_css_class
=
'required'
class
Meta
:
model
=
User
fields
=
[
'groups'
,
'edit_group'
,
'view_group'
]
fields
=
[
'groups'
,
'edit_group
s
'
,
'view_group
s
'
]
labels
=
{
'edit_group'
:
"Edit profile group"
,
'view_group'
:
"View profile group"
,
'edit_group
s
'
:
"Edit profile group"
,
'view_group
s
'
:
"View profile group"
,
}
help_texts
=
{
'edit_group'
:
"Groups that can edit this user's profile"
,
'view_group'
:
"Groups that can view this user's profile"
,
'edit_group
s
'
:
"Groups that can edit this user's profile"
,
'view_group
s
'
:
"Groups that can view this user's profile"
,
'groups'
:
"Which groups this user belongs to"
,
}
widgets
=
{
'groups'
:
CheckboxSelectMultiple
,
'user_permissions'
:
CheckboxSelectMultiple
,
'edit_group'
:
CheckboxSelectMultiple
,
'view_group'
:
CheckboxSelectMultiple
,
'edit_group
s
'
:
CheckboxSelectMultiple
,
'view_group
s
'
:
CheckboxSelectMultiple
,
}
class
PagePropForm
(
forms
.
ModelForm
):
...
...
@@ -49,16 +49,16 @@ class PagePropForm(forms.ModelForm):
required_css_class
=
'required'
class
Meta
:
model
=
Page
fields
=
[
'parent'
,
'name'
,
'owner_group'
,
'edit_group'
,
'view_group'
,
]
fields
=
[
'parent'
,
'name'
,
'owner_group'
,
'edit_group
s
'
,
'view_group
s
'
,
]
widgets
=
{
'edit_group'
:
CheckboxSelectMultiple
,
'view_group'
:
CheckboxSelectMultiple
,
'edit_group
s
'
:
CheckboxSelectMultiple
,
'view_group
s
'
:
CheckboxSelectMultiple
,
}
def
__init__
(
self
,
*
arg
,
**
kwargs
):
super
(
PagePropForm
,
self
).
__init__
(
*
arg
,
**
kwargs
)
self
.
fields
[
'edit_group'
].
required
=
False
self
.
fields
[
'view_group'
].
required
=
False
self
.
fields
[
'edit_group
s
'
].
required
=
False
self
.
fields
[
'view_group
s
'
].
required
=
False
class
GroupEditForm
(
forms
.
ModelForm
):
...
...
core/views/page.py
View file @
a14d940d
...
...
@@ -9,7 +9,7 @@ from core.models import Page, PageRev, LockError
from
core.views.forms
import
PagePropForm
from
core.views
import
CanViewMixin
,
CanEditMixin
,
CanEditPropMixin
class
PageListView
(
ListView
):
class
PageListView
(
CanViewMixin
,
ListView
):
model
=
Page
template_name
=
'core/page_list.jinja'
...
...
sith/settings.py
View file @
a14d940d
...
...
@@ -93,6 +93,11 @@ TEMPLATES = [
"filters"
:
{
"markdown"
:
"core.templatetags.renderer.markdown"
,
},
"globals"
:
{
"can_edit_prop"
:
"core.views.can_edit_prop"
,
"can_edit"
:
"core.views.can_edit"
,
"can_view"
:
"core.views.can_view"
,
},
"bytecode_cache"
:
{
"name"
:
"default"
,
"backend"
:
"django_jinja.cache.BytecodeCache"
,
...
...
@@ -228,12 +233,11 @@ AE_SUBSCRIPTIONS = {
CLUB_ROLES
=
{
10
:
'Président'
,
9
:
'Vice-Président'
,
8
:
'Vice-Président'
,
7
:
'Trésorier'
,
5
:
'Responsable com'
,
4
:
'Secrétaire'
,
3
:
'Responsable info'
,
2
:
'Membre du bureau'
,
1
:
'Membre actif'
,
0
:
'
Membre
'
,
0
:
'
Curieux
'
,
}
subscription/models.py
View file @
a14d940d
...
...
@@ -20,8 +20,12 @@ class Subscriber(User):
class
Meta
:
proxy
=
True
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
Subscriber
,
self
).
__init__
(
*
args
,
**
kwargs
)
def
is_subscribed
(
self
):
return
self
.
subscriptions
.
last
().
is_valid_now
()
s
=
self
.
subscriptions
.
last
()
return
s
.
is_valid_now
()
if
s
is
not
None
else
False
class
Subscription
(
models
.
Model
):
member
=
models
.
ForeignKey
(
Subscriber
,
related_name
=
'subscriptions'
)
...
...
subscription/views.py
View file @
a14d940d
from
django.shortcuts
import
render
from
django.views.generic.edit
import
UpdateView
,
CreateView
from
django.views.generic.base
import
View
from
django.core.exceptions
import
PermissionDenied
from
django
import
forms
from
django.forms
import
Select
from
django.conf
import
settings
from
subscription.models
import
Subscriber
,
Subscription
from
core.views
import
CanEditMixin
,
CanEditPropMixin
,
CanViewMixin
from
core.models
import
User