Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
R
re2o
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Nounous
re2o
Commits
84a901e3
Commit
84a901e3
authored
May 07, 2018
by
Hugo LEVY-FALK
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Documentation des décorateurs d'ACL
parent
586321fd
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
98 additions
and
26 deletions
+98
-26
re2o/acl.py
re2o/acl.py
+98
-26
No files found.
re2o/acl.py
View file @
84a901e3
...
...
@@ -37,24 +37,89 @@ from django.urls import reverse
def
acl_base_decorator
(
method_name
,
*
targets
,
**
kwargs
):
"""Base decorator for acl. It checks if the user has the permission by
calling model.method_name. If the flag on_instance is True, tries to get an
instance of the model by calling model.get_instance(*args, **kwargs) and
runs instance.mehod_name rather than model.method_name.
"""Base decorator for acl. It checks if the `request.user` has the
permission by calling model.method_name. If the flag on_instance is True,
tries to get an instance of the model by calling
`model.get_instance(*args, **kwargs)` and runs `instance.mehod_name`
rather than model.method_name.
It is not intended to be used as is. It is a base for others ACL
decorators.
Args:
method_name: The name of the method which is to to be used for ACL.
(ex: 'can_edit') WARNING: if no method called 'method_name' exists,
then no error will be triggered, the decorator will act as if
permission was granted. This is to allow you to run ACL tests on
fields only. If the method exists, it has to return a 2-tuple
`(can, reason)` with `can` being a boolean stating whether the
access is granted and `reason` a message to be displayed if `can`
equals `False` (can be `None`)
*targets: The targets. Targets are specified like a sequence of models
and fields names. As an example
```
acl_base_decorator('can_edit', ModelA, 'field1', 'field2',
\
ModelB, ModelC, 'field3', on_instance=False)
```
will make the following calls (where `user` is the current user,
`*args` and `**kwargs` are the arguments initially passed to the
view):
- `ModelA.can_edit(user, *args, **kwargs)`
- `ModelA.can_change_field1(user, *args, **kwargs)`
- `ModelA.can_change_field2(user, *args, **kwargs)`
- `ModelB.can_edit(user, *args, **kwargs)`
- `ModelC.can_edit(user, *args, **kwargs)`
- `ModelC.can_change_field3(user, *args, **kwargs)`
Note that
```
acl_base_decorator('can_edit', 'field1', ModelA, 'field2',
\
on_instance=False)
```
would have the same effect that
```
acl_base_decorator('can_edit', ModelA, 'field1', 'field2',
\
on_instance=False)
```
But don't do that, it's silly.
**kwargs: There is only one keyword argument, `on_instance`, which
default value is `True`. When `on_instance` equals `False`, the
decorator runs the ACL method on the model class rather than on
an instance. If an instance need to fetched, it is done calling the
assumed existing method `get_instance` of the model, with the
arguments originally passed to the view.
Returns:
The user is either redirected to their own page with an explanation
message if at least one access is not granted, or to the view. In order
to avoid duplicate DB calls, when the `on_instance` flag equals `True`,
the instances are passed to the view. Example, with this decorator:
```
acl_base_decorator('can_edit', ModelA, 'field1', 'field2', ModelB,
\
ModelC)
```
The view will be called like this:
```
view(request, instance_of_A, instance_of_b, *args, **kwargs)
```
where `*args` and `**kwargs` are the original view arguments.
"""
on_instance
=
kwargs
.
get
(
'on_instance'
,
True
)
def
group_targets
():
"""This generator parses the targets of the decorator, yielding
2-tuples of (model, [fields]).
"""
current_target
=
None
current_fields
=
[]
for
t
in
targets
:
if
isinstance
(
t
,
type
)
and
issubclass
(
t
,
Model
):
for
t
arget
in
targets
:
if
isinstance
(
t
arget
,
type
)
and
issubclass
(
targe
t
,
Model
):
if
current_target
:
yield
(
current_target
,
current_fields
)
current_target
=
t
current_target
=
t
arget
current_fields
=
[]
else
:
current_fields
.
append
(
t
)
current_fields
.
append
(
t
arget
)
yield
(
current_target
,
current_fields
)
def
decorator
(
view
):
...
...
@@ -65,6 +130,11 @@ def acl_base_decorator(method_name, *targets, **kwargs):
instances
=
[]
def
process_target
(
target
,
fields
):
"""This function calls the methods on the target and checks for
the can_change_`field` method with the given fields. It also
stores the instances of models in order to avoid duplicate DB
calls for the view.
"""
if
on_instance
:
try
:
target
=
target
.
get_instance
(
*
args
,
**
kwargs
)
...
...
@@ -97,37 +167,37 @@ def acl_base_decorator(method_name, *targets, **kwargs):
def
can_create
(
*
models
):
"""Decorator to check if an user can create a model.
It assumes that a valid user exists in the request and that the model has a
method can_create(user) which returns true if the user can create this kind
of models.
"""Decorator to check if an user can create the given models. It runs
`acl_base_decorator` with the flag `on_instance=False` and the method
'can_create'. See `acl_base_decorator` documentation for further details.
"""
return
acl_base_decorator
(
'can_create'
,
*
models
,
on_instance
=
False
)
def
can_edit
(
*
targets
):
"""Decorator to check if an user can edit a model.
It tries to get an instance of the model, using
`model.get_instance(*args, **kwargs)` and assumes that the model has a
method `can_edit(user)` which returns `true` if the user can edit this
kind of models.
"""Decorator to check if an user can edit the models.
It runs `acl_base_decorator` with the flag `on_instance=True` and the
method 'can_edit'. See `acl_base_decorator` documentation for further
details.
"""
return
acl_base_decorator
(
'can_edit'
,
*
targets
)
def
can_change
(
*
targets
):
"""Decorator to check if an user can edit a field of a model class.
Difference with can_edit : take a class and not an instance
Difference with can_edit : takes a class and not an instance
It runs `acl_base_decorator` with the flag `on_instance=False` and the
method 'can_change'. See `acl_base_decorator` documentation for further
details.
"""
return
acl_base_decorator
(
'can_change'
,
*
targets
)
def
can_delete
(
*
targets
):
"""Decorator to check if an user can delete a model.
It tries to get an instance of the model, using
`model.get_instance(*args, **kwargs)` and assumes that the model has a
method `can_delete(user)` which returns `true` if the user can delete this
kind of models.
It runs `acl_base_decorator` with the flag `on_instance=True` and the
method 'can_edit'. See `acl_base_decorator` documentation for further
details.
"""
return
acl_base_decorator
(
'can_delete'
,
*
targets
)
...
...
@@ -162,16 +232,18 @@ def can_delete_set(model):
def
can_view
(
*
targets
):
"""Decorator to check if an user can view a model.
It tries to get an instance of the model, using
`model.get_instance(*args, **kwargs)` and assumes that the model has a
method `can_view(user)` which returns `true` if the user can view this
kind of models.
It runs `acl_base_decorator` with the flag `on_instance=True` and the
method 'can_view'. See `acl_base_decorator` documentation for further
details.
"""
return
acl_base_decorator
(
'can_view'
,
*
targets
)
def
can_view_all
(
*
targets
):
"""Decorator to check if an user can view a class of model.
It runs `acl_base_decorator` with the flag `on_instance=False` and the
method 'can_view_all'. See `acl_base_decorator` documentation for further
details.
"""
return
acl_base_decorator
(
'can_view_all'
,
*
targets
,
on_instance
=
False
)
...
...
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