Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Debian New Member Process
nm.debian.org
Commits
9bc9adf8
Commit
9bc9adf8
authored
Jun 01, 2016
by
Enrico Zini
Browse files
Refactored Permissions sytem
parent
c64e62d0
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
backend/models.py
View file @
9bc9adf8
...
@@ -28,7 +28,27 @@ PROCESS_MAILBOX_DIR = getattr(settings, "PROCESS_MAILBOX_DIR", "/srv/nm.debian.o
...
@@ -28,7 +28,27 @@ PROCESS_MAILBOX_DIR = getattr(settings, "PROCESS_MAILBOX_DIR", "/srv/nm.debian.o
DM_IMPORT_DATE
=
getattr
(
settings
,
"DM_IMPORT_DATE"
,
None
)
DM_IMPORT_DATE
=
getattr
(
settings
,
"DM_IMPORT_DATE"
,
None
)
class
PersonVisitorPermissions
(
object
):
class
Permissions
(
set
):
"""
Set of strings, each string represent a permission
"""
@
property
def
perms
(
self
):
"""
Compatibility property for old code doing if "foo" in vperms.perms
"""
return
self
class
VisitorPermissions
(
Permissions
):
"""
Permissions of a visitor regardless of context
"""
def
__init__
(
self
,
visitor
):
self
.
visitor
=
visitor
class
PersonVisitorPermissions
(
VisitorPermissions
):
"""
"""
Store NM-specific permissions
Store NM-specific permissions
"""
"""
...
@@ -42,156 +62,79 @@ class PersonVisitorPermissions(object):
...
@@ -42,156 +62,79 @@ class PersonVisitorPermissions(object):
dd
=
frozenset
((
const
.
STATUS_DD_U
,
const
.
STATUS_DD_NU
))
dd
=
frozenset
((
const
.
STATUS_DD_U
,
const
.
STATUS_DD_NU
))
def
__init__
(
self
,
person
,
visitor
):
def
__init__
(
self
,
person
,
visitor
):
super
(
PersonVisitorPermissions
,
self
).
__init__
(
visitor
)
# Person being visited
# Person being visited
self
.
person
=
person
.
person
self
.
person
=
person
.
person
# Person doing the visit
self
.
visitor
=
visitor
.
person
if
visitor
else
None
# Processes of self.person
# Processes of self.person
self
.
processes
=
list
(
self
.
person
.
processes
.
all
())
#self.processes = list(self.person.processes.all())
@
cached_property
def
_is_current_advocate
(
self
):
"""
Return True if the visitor is the advocate of any active process not in
FD/DAM hands
"""
if
self
.
visitor
is
None
:
return
False
for
p
in
self
.
processes
:
if
not
p
.
is_active
:
continue
if
p
.
progress
in
self
.
fddam_states
:
continue
if
p
.
advocates
.
filter
(
pk
=
self
.
visitor
.
pk
).
exists
():
return
True
return
False
@
cached_property
def
_can_edit_bio
(
self
):
"""
Visitor can edit the person's bio
"""
if
self
.
visitor
is
None
:
return
False
if
self
.
visitor
.
is_admin
:
return
True
if
self
.
person
.
pending
:
return
False
if
self
.
visitor
.
pk
==
self
.
person
.
pk
:
return
True
return
self
.
visitor
.
is_active_am
@
cached_property
def
_can_update_keycheck
(
self
):
"""
Visitor can refresh keycheck results
"""
if
self
.
visitor
is
None
:
return
False
if
self
.
visitor
.
is_admin
:
return
True
if
self
.
person
.
pending
:
return
False
if
self
.
visitor
.
pk
==
self
.
person
.
pk
:
return
True
return
self
.
visitor
.
is_active_am
or
self
.
_is_current_advocate
@
cached_property
def
_has_ldap_record
(
self
):
"""
The person already has an LDAP record
"""
# If the person is already in LDAP, then nobody can edit their LDAP
# If the person is already in LDAP, then nobody can edit their LDAP
# info, since this database then becomes a read-only mirror of LDAP
# info, since this database then becomes a read-only mirror of LDAP
return
self
.
person
.
status
not
in
(
const
.
STATUS_DC
,
const
.
STATUS_DM
)
self
.
person_has_ldap_record
=
self
.
person
.
status
not
in
(
const
.
STATUS_DC
,
const
.
STATUS_DM
)
@
cached_property
# Possible new statuses that the person can have
def
_can_edit_ldap_fields
(
self
):
self
.
person_possible_new_statuses
=
self
.
person
.
possible_new_statuses
"""
The visitor can edit the person's LDAP fields
# True if there are active processes currently frozen for review
"""
self
.
person_has_frozen_processes
=
False
if
self
.
visitor
is
None
:
return
False
old_frozen_progesses
=
frozenset
((
const
.
PROGRESS_AM_OK
,
# LDAP fields are immutable in nm.debian.org when there is already an
const
.
PROGRESS_FD_HOLD
,
# LDAP record
const
.
PROGRESS_FD_OK
,
if
self
.
_has_ldap_record
:
return
False
const
.
PROGRESS_DAM_HOLD
,
const
.
PROGRESS_DAM_OK
,
# FD and DAM can do everything except mess with LDAP
const
.
PROGRESS_DONE
,
if
self
.
visitor
.
is_admin
:
return
True
const
.
PROGRESS_CANCELLED
,
))
# Only the person themselves, or an am, can potentially edit LDAP
import
process.models
as
pmodels
# fields
if
pmodels
.
Process
.
objects
.
filter
(
person
=
self
.
person
,
frozen_by__isnull
=
False
).
exists
():
if
self
.
person
.
pk
!=
self
.
visitor
.
pk
and
not
self
.
visitor
.
is_active_am
:
return
False
self
.
person_has_frozen_processes
=
True
elif
Process
.
objects
.
filter
(
person
=
self
.
person
,
is_active
=
True
,
progress__in
=
old_frozen_progesses
).
exists
():
# Check if there is some process in a state for which nobody should
self
.
person_has_frozen_processes
=
True
# interfere
if
self
.
visitor
is
None
:
# Pending person records cannot be changed
pass
if
self
.
person
.
pending
:
return
False
elif
self
.
visitor
.
is_admin
:
self
.
_compute_admin_perms
()
# If there are active processes in FD or DAM's hand, only them can
elif
self
.
visitor
==
self
.
person
:
# change them
self
.
_compute_own_perms
()
for
p
in
self
.
processes
:
elif
self
.
visitor
.
is_active_am
:
if
not
p
.
is_active
:
continue
self
.
_compute_active_am_perms
()
if
p
.
progress
in
(
elif
self
.
visitor
.
is_dd
:
const
.
PROGRESS_AM_OK
,
self
.
_compute_dd_perms
()
const
.
PROGRESS_FD_HOLD
,
const
.
PROGRESS_FD_OK
,
def
_compute_admin_perms
(
self
):
const
.
PROGRESS_DAM_HOLD
,
self
.
update
((
"edit_bio"
,
"update_keycheck"
,
"view_person_audit_log"
))
const
.
PROGRESS_DAM_OK
,
if
self
.
person_possible_new_statuses
:
self
.
add
(
"request_new_status"
)
const
.
PROGRESS_DONE
,
if
not
self
.
person_has_ldap_record
:
self
.
add
(
"edit_ldap"
)
const
.
PROGRESS_CANCELLED
,
):
def
_compute_own_perms
(
self
):
return
False
self
.
update
((
"update_keycheck"
,
"view_person_audit_log"
))
if
not
self
.
person_has_frozen_processes
:
return
True
if
not
self
.
person_has_ldap_record
and
not
self
.
person
.
pending
:
self
.
add
(
"edit_ldap"
)
@
cached_property
self
.
add
(
"edit_bio"
)
def
_can_view_person_audit_log
(
self
):
if
self
.
person
.
pending
:
return
"""
if
self
.
person_possible_new_statuses
:
self
.
add
(
"request_new_status"
)
The visitor can view the person's audit log
"""
def
_compute_active_am_perms
(
self
):
# Anonymous cannot see it
self
.
update
((
"update_keycheck"
,
"view_person_audit_log"
))
if
self
.
visitor
is
None
:
return
False
if
not
self
.
person_has_frozen_processes
:
self
.
add
(
"edit_bio"
)
# The person can see it
if
not
self
.
person_has_ldap_record
:
self
.
add
(
"edit_ldap"
)
if
self
.
visitor
.
pk
==
self
.
person
.
pk
:
return
True
def
_compute_dd_perms
(
self
):
# Any DD can see it
self
.
update
((
"update_keycheck"
,
"view_person_audit_log"
))
if
self
.
visitor
.
status
in
self
.
dd
:
return
True
# TODO: advocate view audit log
# The advocate can see it
# (note, a DM can be advocate for a DC requesting a guest account)
if
self
.
_is_current_advocate
:
return
True
return
False
@
cached_property
def
_can_request_new_status
(
self
):
"""
The visitor can request a new status for the person
"""
# Anonymous cannot see it
if
self
.
visitor
is
None
:
return
False
# Only the person and admins can request a new status
if
self
.
visitor
.
pk
!=
self
.
person
.
pk
and
not
self
.
visitor
.
is_admin
:
return
False
# There should be some new status possible
return
bool
(
self
.
person
.
possible_new_statuses
)
def
_compute_perms
(
self
):
"""
Compute the set of permission tags
"""
res
=
set
()
if
self
.
_can_edit_bio
:
res
.
add
(
"edit_bio"
)
if
self
.
_can_update_keycheck
:
res
.
add
(
"update_keycheck"
)
if
self
.
_can_edit_ldap_fields
:
res
.
add
(
"edit_ldap"
)
if
self
.
_can_view_person_audit_log
:
res
.
add
(
"view_person_audit_log"
)
if
self
.
_can_request_new_status
:
res
.
add
(
"request_new_status"
)
return
res
@
cached_property
def
perms
(
self
):
"""
Compute the set of permission tags
"""
return
frozenset
(
self
.
_compute_perms
())
@
cached_property
@
cached_property
def
advocate_targets
(
self
):
def
advocate_targets
(
self
):
"""
"""
Return a list of statuses for which the current visitor can become an
Return a list of statuses for which the current visitor can become an
advocate
advocate
This is used only when starting old-style processes
"""
"""
# Nothing can happen while the person is pending confirmation
# Nothing can happen while the person is pending confirmation
if
self
.
person
.
pending
:
return
[]
if
self
.
person
.
pending
:
return
[]
...
@@ -206,9 +149,10 @@ class PersonVisitorPermissions(object):
...
@@ -206,9 +149,10 @@ class PersonVisitorPermissions(object):
if
am
is
not
None
:
pks
.
add
(
am
.
person
.
pk
)
if
am
is
not
None
:
pks
.
add
(
am
.
person
.
pk
)
return
pks
return
pks
active_processes
=
list
(
self
.
person
.
processes
.
filter
(
is_active
=
True
))
def
can_add_advocate
(
*
applying_for
):
def
can_add_advocate
(
*
applying_for
):
for
p
in
self
.
processes
:
for
p
in
active_processes
:
if
not
p
.
is_active
:
continue
if
p
.
applying_for
not
in
applying_for
:
continue
if
p
.
applying_for
not
in
applying_for
:
continue
if
p
.
progress
in
self
.
fddam_states
:
return
False
if
p
.
progress
in
self
.
fddam_states
:
return
False
if
self
.
visitor
.
pk
in
involved_pks
(
p
):
return
False
if
self
.
visitor
.
pk
in
involved_pks
(
p
):
return
False
...
@@ -257,29 +201,23 @@ class PersonVisitorPermissions(object):
...
@@ -257,29 +201,23 @@ class PersonVisitorPermissions(object):
# ))
# ))
class
ProcessVisitorPermissions
(
PersonVisitorPermissions
):
class
ProcessVisitorPermissions
(
PersonVisitorPermissions
):
"""
Permissions for visiting old-style Processes
"""
def
__init__
(
self
,
process
,
visitor
):
def
__init__
(
self
,
process
,
visitor
):
super
(
ProcessVisitorPermissions
,
self
).
__init__
(
process
.
person
,
visitor
)
super
(
ProcessVisitorPermissions
,
self
).
__init__
(
process
.
person
,
visitor
)
self
.
process
=
process
self
.
process
=
process
@
cached_property
if
self
.
visitor
is
None
:
def
_can_view_email
(
self
):
pass
"""
elif
self
.
visitor
.
is_admin
:
The visitor can view the process's email archive
self
.
add
(
"view_mbox"
)
"""
elif
self
.
visitor
==
self
.
person
:
if
self
.
visitor
is
None
:
return
False
self
.
add
(
"view_mbox"
)
# Any admins
elif
self
.
visitor
.
is_active_am
:
if
self
.
visitor
.
is_admin
:
return
True
self
.
add
(
"view_mbox"
)
# The person themselves
elif
self
.
process
.
advocates
.
filter
(
pk
=
self
.
visitor
.
pk
).
exists
():
if
self
.
visitor
.
pk
==
self
.
person
.
pk
:
return
True
self
.
add
(
"view_mbox"
)
# Any AM
if
self
.
visitor
.
am_or_none
:
return
True
# The advocates
return
self
.
process
.
advocates
.
filter
(
pk
=
self
.
visitor
.
pk
).
exists
()
def
_compute_perms
(
self
):
res
=
super
(
ProcessVisitorPermissions
,
self
).
_compute_perms
()
if
self
.
_can_view_email
:
res
.
add
(
"view_mbox"
)
return
res
class
PersonManager
(
BaseUserManager
):
class
PersonManager
(
BaseUserManager
):
...
...
backend/tests/test_perms.py
View file @
9bc9adf8
This diff is collapsed.
Click to expand it.
backend/unittest.py
View file @
9bc9adf8
...
@@ -3,6 +3,7 @@ from __future__ import print_function
...
@@ -3,6 +3,7 @@ from __future__ import print_function
from
__future__
import
absolute_import
from
__future__
import
absolute_import
from
__future__
import
division
from
__future__
import
division
from
__future__
import
unicode_literals
from
__future__
import
unicode_literals
import
backend.models
as
bmodels
from
backend.models
import
Person
,
Process
,
AM
from
backend.models
import
Person
,
Process
,
AM
from
backend
import
const
from
backend
import
const
from
django.utils.timezone
import
now
from
django.utils.timezone
import
now
...
@@ -397,3 +398,52 @@ class PageElements(dict):
...
@@ -397,3 +398,52 @@ class PageElements(dict):
def
add_string
(
self
,
name
,
term
):
def
add_string
(
self
,
name
,
term
):
self
[
name
]
=
re
.
compile
(
r
"""{}"""
.
format
(
re
.
escape
(
term
)))
self
[
name
]
=
re
.
compile
(
r
"""{}"""
.
format
(
re
.
escape
(
term
)))
class
TestOldProcesses
(
NamedObjects
):
def
__init__
(
self
,
**
defaults
):
super
(
TestOldProcesses
,
self
).
__init__
(
bmodels
.
Process
,
**
defaults
)
defaults
.
setdefault
(
"progress"
,
const
.
PROGRESS_APP_NEW
)
def
create
(
self
,
_name
,
advocates
=
[],
**
kw
):
self
.
_update_kwargs_with_defaults
(
_name
,
kw
)
if
"process"
in
kw
:
kw
.
setdefault
(
"is_active"
,
kw
[
"process"
]
not
in
(
const
.
PROGRESS_DONE
,
const
.
PROGRESS_CANCELLED
))
else
:
kw
.
setdefault
(
"is_active"
,
True
)
if
"manager"
in
kw
:
try
:
am
=
kw
[
"manager"
].
am
except
bmodels
.
AM
.
DoesNotExist
:
am
=
bmodels
.
AM
.
objects
.
create
(
person
=
kw
[
"manager"
])
kw
[
"manager"
]
=
am
self
[
_name
]
=
o
=
self
.
_model
.
objects
.
create
(
**
kw
)
for
a
in
advocates
:
o
.
advocates
.
add
(
a
)
return
o
class
OldProcessFixtureMixin
(
PersonFixtureMixin
):
@
classmethod
def
get_processes_defaults
(
cls
):
"""
Get default arguments for test processes
"""
return
{}
@
classmethod
def
setUpClass
(
cls
):
super
(
OldProcessFixtureMixin
,
cls
).
setUpClass
()
cls
.
processes
=
TestOldProcesses
(
**
cls
.
get_processes_defaults
())
@
classmethod
def
tearDownClass
(
cls
):
cls
.
processes
.
delete_all
()
super
(
OldProcessFixtureMixin
,
cls
).
tearDownClass
()
def
setUp
(
self
):
super
(
OldProcessFixtureMixin
,
self
).
setUp
()
self
.
processes
.
refresh
();
process/models.py
View file @
9bc9adf8
...
@@ -35,24 +35,16 @@ class ProcessVisitorPermissions(bmodels.PersonVisitorPermissions):
...
@@ -35,24 +35,16 @@ class ProcessVisitorPermissions(bmodels.PersonVisitorPermissions):
super
(
ProcessVisitorPermissions
,
self
).
__init__
(
process
.
person
,
visitor
)
super
(
ProcessVisitorPermissions
,
self
).
__init__
(
process
.
person
,
visitor
)
self
.
process
=
process
self
.
process
=
process
@
cached_property
if
self
.
visitor
is
None
:
def
_can_view_email
(
self
):
pass
"""
elif
self
.
visitor
.
is_admin
:
The visitor can view the process's email archive
self
.
add
(
"view_mbox"
)
"""
elif
self
.
visitor
==
self
.
person
:
if
self
.
visitor
is
None
:
return
False
self
.
add
(
"view_mbox"
)
# Any admins
elif
self
.
visitor
.
is_active_am
:
if
self
.
visitor
.
is_admin
:
return
True
self
.
add
(
"view_mbox"
)
# The person themselves
#elif self.process.advocates.filter(pk=self.visitor.pk).exists():
if
self
.
visitor
.
pk
==
self
.
person
.
pk
:
return
True
# self.add("view_mbox")
# Any active AM
if
self
.
visitor
.
is_active_am
:
return
True
return
False
def
_compute_perms
(
self
):
res
=
super
(
ProcessVisitorPermissions
,
self
).
_compute_perms
()
if
self
.
_can_view_email
:
res
.
add
(
"view_mbox"
)
return
res
class
RequirementVisitorPermissions
(
ProcessVisitorPermissions
):
class
RequirementVisitorPermissions
(
ProcessVisitorPermissions
):
...
@@ -60,38 +52,36 @@ class RequirementVisitorPermissions(ProcessVisitorPermissions):
...
@@ -60,38 +52,36 @@ class RequirementVisitorPermissions(ProcessVisitorPermissions):
super
(
RequirementVisitorPermissions
,
self
).
__init__
(
requirement
.
process
,
visitor
)
super
(
RequirementVisitorPermissions
,
self
).
__init__
(
requirement
.
process
,
visitor
)
self
.
requirement
=
requirement
self
.
requirement
=
requirement
@
cached_property
if
self
.
visitor
is
None
:
def
_can_edit_statements
(
self
):
pass
if
self
.
visitor
is
None
:
return
False
elif
self
.
visitor
.
is_admin
:
if
self
.
visitor
.
is_admin
:
return
True
self
.
add
(
"edit_statements"
)
else
:
if
self
.
requirement
.
type
==
"intent"
:
if
self
.
requirement
.
type
==
"intent"
:
return
self
.
visitor
==
self
.
person
if
self
.
visitor
==
self
.
person
:
self
.
add
(
"edit_statements"
)
elif
self
.
requirement
.
type
==
"sc_dmup"
:
elif
self
.
requirement
.
type
==
"sc_dmup"
:
return
self
.
visitor
==
self
.
person
if
self
.
visitor
==
self
.
person
:
self
.
add
(
"edit_statements"
)
elif
self
.
requirement
.
type
==
"advocate"
:
elif
self
.
requirement
.
type
==
"advocate"
:
if
self
.
process
.
applying_for
==
const
.
STATUS_DC_GA
:
if
self
.
process
.
applying_for
==
const
.
STATUS_DC_GA
:
return
self
.
visitor
.
status
in
(
const
.
STATUS_DM
,
const
.
STATUS_DM_GA
,
const
.
STATUS_DD_NU
,
const
.
STATUS_DD_U
)
if
self
.
visitor
.
status
in
(
const
.
STATUS_DM
,
const
.
STATUS_DM_GA
,
const
.
STATUS_DD_NU
,
const
.
STATUS_DD_U
):
elif
self
.
process
.
applying_for
==
const
.
STATUS_DM
:
self
.
add
(
"edit_statements"
)
return
self
.
visitor
.
status
in
(
const
.
STATUS_DD_NU
,
const
.
STATUS_DD_U
)
elif
self
.
process
.
applying_for
==
const
.
STATUS_DM
:
elif
self
.
process
.
applying_for
==
const
.
STATUS_DM_GA
:
if
self
.
visitor
.
status
in
(
const
.
STATUS_DD_NU
,
const
.
STATUS_DD_U
):
return
self
.
visitor
==
self
.
person
or
self
.
visitor
.
status
in
(
const
.
STATUS_DD_NU
,
const
.
STATUS_DD_U
)
self
.
add
(
"edit_statements"
)
elif
self
.
process
.
applying_for
==
const
.
STATUS_DD_NU
:
elif
self
.
process
.
applying_for
==
const
.
STATUS_DM_GA
:
return
self
.
visitor
.
status
in
(
const
.
STATUS_DD_NU
,
const
.
STATUS_DD_U
)
if
self
.
visitor
==
self
.
person
or
self
.
visitor
.
status
in
(
const
.
STATUS_DD_NU
,
const
.
STATUS_DD_U
):
elif
self
.
process
.
applying_for
==
const
.
STATUS_DD_U
:
self
.
add
(
"edit_statements"
)
return
self
.
visitor
.
status
in
(
const
.
STATUS_DD_NU
,
const
.
STATUS_DD_U
)
elif
self
.
process
.
applying_for
==
const
.
STATUS_DD_NU
:
return
False
if
self
.
visitor
.
status
in
(
const
.
STATUS_DD_NU
,
const
.
STATUS_DD_U
):
elif
self
.
requirement
.
type
==
"am_ok"
:
self
.
add
(
"edit_statements"
)
a
=
self
.
process
.
current_am_assignment
elif
self
.
process
.
applying_for
==
const
.
STATUS_DD_U
:
if
a
is
None
:
return
False
if
self
.
visitor
.
status
in
(
const
.
STATUS_DD_NU
,
const
.
STATUS_DD_U
):
return
a
.
am
.
person
==
self
.
visitor
self
.
add
(
"edit_statements"
)
elif
self
.
requirement
.
type
==
"am_ok"
:
return
False
a
=
self
.
process
.
current_am_assignment
if
a
is
not
None
:
def
_compute_perms
(
self
):
if
a
.
am
.
person
==
self
.
visitor
:
res
=
super
(
RequirementVisitorPermissions
,
self
).
_compute_perms
()
self
.
add
(
"edit_statements"
)
if
self
.
_can_edit_statements
:
res
.
add
(
"edit_statements"
)
return
res
class
ProcessManager
(
models
.
Manager
):
class
ProcessManager
(
models
.
Manager
):
...
...
process/tests/test_perms.py
View file @
9bc9adf8
...
@@ -253,7 +253,7 @@ class TestVisitApplicant(ProcessFixtureMixin, TestCase):
...
@@ -253,7 +253,7 @@ class TestVisitApplicant(ProcessFixtureMixin, TestCase):
expected
.
advs
.
set
(
"fd dam dd_nu dd_u"
,
"dc_ga dm dd_u dd_nu"
)
expected
.
advs
.
set
(
"fd dam dd_nu dd_u"
,
"dc_ga dm dd_u dd_nu"
)
expected
.
advs
.
set
(
"adv dm dm_ga"
,
"dc_ga"
)
expected
.
advs
.
set
(
"adv dm dm_ga"
,
"dc_ga"
)
expected
.
proc
.
set
(
"fd dam app"
,
"update_keycheck edit_bio edit_ldap view_person_audit_log view_mbox request_new_status"
)
expected
.
proc
.
set
(
"fd dam app"
,
"update_keycheck edit_bio edit_ldap view_person_audit_log view_mbox request_new_status"
)
expected
.
proc
.
set
(
"dd_nu dd_u"
,
"view_person_audit_log"
)
expected
.
proc
.
set
(
"dd_nu dd_u"
,
"view_person_audit_log
update_keycheck
"
)
expected
.
intent
.
set
(
"fd dam app"
,
"edit_statements"
)
expected
.
intent
.
set
(
"fd dam app"
,
"edit_statements"
)
expected
.
sc_dmup
.
set
(
"fd dam app"
,
"edit_statements"
)
expected
.
sc_dmup
.
set
(
"fd dam app"
,
"edit_statements"
)
expected
.
advocate
.
set
(
"fd dam adv dd_nu dd_u dm dm_ga"
,
"edit_statements"
)
expected
.
advocate
.
set
(
"fd dam adv dd_nu dd_u dm dm_ga"
,
"edit_statements"
)
...
...
restricted/tests/test_permissions.py
View file @
9bc9adf8
# coding: utf8
# coding: utf8
"""
Test permissions
"""
from
__future__
import
print_function
from
__future__
import
print_function
from
__future__
import
absolute_import
from
__future__
import
absolute_import
from
__future__
import
division
from
__future__
import
division
...
@@ -9,6 +6,7 @@ from __future__ import unicode_literals
...
@@ -9,6 +6,7 @@ from __future__ import unicode_literals
from
django.test
import
TestCase
,
TransactionTestCase
from
django.test
import
TestCase
,
TransactionTestCase
from
backend
import
const
from
backend
import
const
from
backend.test_common
import
*
from
backend.test_common
import
*
from
backend.unittest
import
PersonFixtureMixin
,
OldProcessFixtureMixin
import
backend.models
as
bmodels
import
backend.models
as
bmodels
class
PermissionsTestCase
(
NMBasicFixtureMixin
,
NMTestUtilsMixin
,
TestCase
):
class
PermissionsTestCase
(
NMBasicFixtureMixin
,
NMTestUtilsMixin
,
TestCase
):
...
@@ -226,92 +224,87 @@ class AssignAMAgainTestCase(NMBasicFixtureMixin, NMTestUtilsMixin, TestCase):
...
@@ -226,92 +224,87 @@ class AssignAMAgainTestCase(NMBasicFixtureMixin, NMTestUtilsMixin, TestCase):
# TODO: post
# TODO: post
class
PersonTestCase
(
NMBasicFixtureMixin
,
NMTestUtilsMixin
,
TransactionTestCase
):
class
PersonTestCase
(
OldProcessFixtureMixin
,
TestCase
):
def
setUp
(
self
):
@
classmethod
super
(
PersonTestCase
,
self
).
setUp
()
def
setUpClass
(
cls
):
self
.
app
=
self
.
make_user
(
"app"
,
const
.
STATUS_DC
,
alioth
=
True
,
fd_comment
=
"FD_COMMENTS"
)
super
(
PersonTestCase
,
cls
).
setUpClass
()
self
.
adv
=
self
.
make_user
(
"adv"
,
const
.
STATUS_DD_NU
)
cls
.
persons
.
create
(
"app"
,
status
=
const
.
STATUS_DC
,
alioth
=
True
,
fd_comment
=
"FD_COMMENTS"
)
self
.
am
=
self
.
make_user
(
"am"
,
const
.
STATUS_DD_NU
)
cls
.
persons
.
create
(
"adv"
,
status
=
const
.
STATUS_DD_NU
)
self
.
proc
=
self
.
make_process
(
self
.
app
,
const
.
STATUS_DD_NU
,
const
.
PROGRESS_AM
,
manager
=
self
.
am
,
advocates
=
[
self
.
adv
])
cls
.
persons
.
create
(
"am"
,
status
=
const
.
STATUS_DD_NU
)
cls
.
processes
.
create
(
"app"
,
person
=
cls
.
persons
.
app
,
applying_for
=
const
.
STATUS_DD_NU
,
progress
=
const
.
PROGRESS_AM
,
manager
=
cls
.
persons
.
am
,
advocates
=
[
cls
.
persons
.
adv
])
def
test_person
(
self
):
class
WhenView
(
NMTestUtilsWhen
):
@
classmethod
url
=
reverse
(
"restricted_person"
,
kwargs
=
{
"key"
:
self
.
users
[
"app"
].
lookup_key
})
def
__add_extra_tests__
(
cls
):
allowed
=
frozenset
((
"app"
,
"adv"
,
"am"
,
"fd"
,
"dam"
))
# Anonymous cannot see or post to anyone's page
self
.
assertVisit
(
WhenView
(),
ThenForbidden
())
for
visited
in
(
"pending"
,
"dc"
,
"dc_ga"
,
"dm"
,
"dm_ga"
,
"dd_nu"
,
"dd_u"
,
"dd_e"
,
"dd_r"
,
"app"
,
"adv"
,
"am"
,
"fd"
,
"dam"
):
for
u
in
self
.
users
.
viewkeys
()
-
allowed
:
cls
.
_add_method
(
cls
.
_test_get_forbidden
,
None
,
visited
)
self
.
assertVisit
(
WhenView
(
user
=
self
.
users
[
u
]),
ThenForbidden
())
cls
.
_add_method
(
cls
.
_test_post_forbidden
,
None
,
visited
)
for
u
in
allowed
:
self
.
assertVisit
(
WhenView
(
user
=
self
.
users
[
u
]),
ThenSuccess
())
# Only app, adv, am, fd, dam can edit other people's LDAP information
for
visitor
in
(
"pending"
,
"dc"
,
"dc_ga"
,
"dm"
,
"dm_ga"
,
"dd_nu"
,
"dd_u"
,
"dd_e"
,
"dd_r"
,
"app"
,
"adv"
,
"am"
,
"fd"
,
"dam"
):
def
test_post
(
self
):
for
visited
in
(
"pending"
,
"dc"
,
"dc_ga"
,
"dm"
,
"dm_ga"
,
"dd_nu"
,
"dd_u"
,
"dd_e"
,
"dd_r"
,
"app"
,
"adv"
,
"am"
,
"fd"
,
"dam"
):
users
=
self
.
users
cls
.
_add_method
(
cls
.
_test_maybe_allowed
,
visitor
,
visited
)
class
WhenPost
(
NMTestUtilsWhen
):
method
=
"post"
def
_test_get_forbidden
(
self
,
visitor
,
visited
):
def
__init__
(
self
,
user
=
None
,
person
=
None
,
**
kw
):
client
=
self
.
make_test_client
(
visitor
)
user
=
users
[
user
]
if
user
else
None
response
=
client
.
get
(
reverse
(
"restricted_person"
,
kwargs
=
{
"key"
:
self
.
persons
[
visited
].
lookup_key
}))
self
.
person
=
users
[
person
]
self
.
assertPermissionDenied
(
response
)
data
=
{
"cn"
:
"Z"
,
"fd_comment"
:
"Z"
,
"bio"
:
"Z"
,
"email"
:
self
.
person
.
email
,
"status"
:
const
.
STATUS_DC
}
self
.
orig_cn
=
self
.
person
.
cn
def
_test_post_forbidden
(
self
,
visitor
,
visited
):
self
.
orig_fd
=
self
.
person
.
fd_comment
client
=
self
.
make_test_client
(
visitor
)
self
.
orig_bio
=
self
.
person
.
bio
visited
=
self
.
persons
[
visited
]
self
.
orig_status
=
self
.
person
.
status
orig_cn
=
visited
.
cn
super
(
WhenPost
,
self
).
__init__
(
user
=
user
,
data
=
data
,
url
=
reverse
(
"restricted_person"
,
kwargs
=
{
"key"
:
self
.
person
.
lookup_key
}),
**
kw
)
orig_fd_comment
=
visited
.
fd_comment
def
tearDown
(
self
,
fixture
):
orig_bio
=
visited
.
bio
super
(
WhenPost
,
self
).
tearDown
(
fixture
)
orig_email
=
visited
.
email
self
.
person
.
cn
=
self
.
orig_cn
orig_status
=
visited
.
status
self
.
person
.
fd_comment
=
self
.
orig_fd
response
=
client
.
post
(
reverse
(
"restricted_person"
,
kwargs
=
{
"key"
:
visited
.
lookup_key
}),
data
=
{
self
.
person
.
bio
=
self
.
orig_bio
"cn"
:
"Z"
,
"fd_comment"
:
"Z"
,
"bio"
:
"Z"
,
"email"
:
"foo@example.org"
,
"status"
:
const
.
STATUS_DC
self
.
person
.
status
=
self
.
orig_status
})
self
.
person
.
save
(
audit_skip
=
True
)
self
.
assertPermissionDenied
(
response
)
visited
.
refresh_from_db
()
class
ThenChanges
(
ThenRedirect
):
self
.
assertEquals
(
visited
.
cn
,
orig_cn
)
def
__init__
(
self
,
cn
=
False
,
fd
=
False
,
bio
=
False
,
status
=
False
):
self
.
assertEquals
(
visited
.
fd_comment
,
orig_fd_comment
)
self
.
cn
,
self
.
fd
,
self
.
bio
,
self
.
status
=
cn
,
fd
,
bio
,
status
self
.
assertEquals
(
visited
.
bio
,
orig_bio
)
def
__call__
(
self
,
fixture
,
response
,
when
,
test_client
):
self
.
assertEquals
(
visited
.
email
,
orig_email
)
super
(
ThenChanges
,
self
).
__call__
(
fixture
,
response
,
when
,
test_client
)
self
.
assertEquals
(
visited
.
status
,
orig_status
)
person
=
bmodels
.
Person
.
objects
.
get
(
pk
=
when
.
person
.
pk
)
if
self
.
cn
:
def
_test_maybe_allowed
(
self
,
visitor
,
visited
):
fixture
.
assertEquals
(
person
.
cn
,
"Z"
)
# Just check that the actions correspond to the right permissions. That
else
:
# the permissions are right is checked elsewhere
fixture
.
assertEquals
(
person
.
cn
,
when
.
orig_cn
)
visit_perms
=
self
.
persons
[
visited
].
permissions_of
(
self
.
persons
[
visitor
])
if
self
.
fd
:
if
"edit_ldap"
not
in
visit_perms
and
"edit_bio"
not
in
visit_perms
:
fixture
.
assertEquals
(
person
.
fd_comment
,
"Z"
)
self
.
_test_post_forbidden
(
visitor
,
visited
)
else
:
return
fixture
.
assertEquals
(
person
.
fd_comment
,
when
.
orig_fd
)
if
self
.
bio
:
client
=
self
.
make_test_client
(
visitor
)
fixture
.
assertEquals
(
person
.
bio
,
"Z"
)
visited
=
self
.
persons
[
visited
]
else
:
orig_cn
=
visited
.
cn
fixture
.
assertEquals
(
person
.
bio
,
when
.
orig_bio
)
orig_fd_comment
=
visited
.
fd_comment
if
self
.
status
:
orig_bio
=
visited
.
bio
fixture
.
assertEquals
(
person
.
status
,
const
.
STATUS_DC
)
orig_email
=
visited
.
email
else
:
orig_status
=
visited
.
status
fixture
.
assertEquals
(
person
.
status
,
when
.
orig_status
)
new_status
=
const
.
STATUS_DC
if
visited
.
status
!=
const
.
STATUS_DC
else
const
.
STATUS_DM
# Anonymous cannot post to anything
response
=
client
.
post
(
reverse
(
"restricted_person"
,
kwargs
=
{
"key"
:
visited
.
lookup_key
}),
data
=
{
for
u
in
self
.
users
.
viewkeys
():
"cn"
:
"Z"
,
"fd_comment"
:
"Z"
,
"bio"
:
"Z"
,
"email"
:
"foo@example.org"
,
"status"
:
new_status
self
.
assertVisit
(
WhenPost
(
person
=
u
),
ThenForbidden
())
})
visited
.
refresh_from_db
()
for
u
in
self
.
users
.
viewkeys
()
-
frozenset
((
"app"
,
"adv"
,
"am"
,
"fd"
,
"dam"
)):
self
.
assertRedirectMatches
(
response
,
visited
.
get_absolute_url
())
self
.
assertVisit
(
WhenPost
(
user
=
u
,
person
=
"app"
),
ThenForbidden
())
self
.
assertVisit
(
WhenPost
(
user
=
"app"
,
person
=
"app"
),
ThenChanges
(
True
,
False
,
True
,
False
))
if
"edit_ldap"
in
visit_perms
:
self
.
assertVisit
(
WhenPost
(
user
=
"adv"
,
person
=
"app"
),
ThenChanges
(
True
,
False
,
True
,
False
))
self
.
assertEquals
(
visited
.
cn
,
"Z"
)
self
.
assertVisit
(
WhenPost
(
user
=
"am"
,
person
=
"app"
),
ThenChanges
(
True
,
False
,
True
,
False
))
self
.
assertEquals
(
visited
.
email
,
"foo@example.org"
)
self
.
assertVisit
(
WhenPost
(
user
=
"fd"
,
person
=
"app"
),
ThenChanges
(
True
,
True
,
True
,
True
))
else
:
self
.
assertVisit
(
WhenPost
(
user
=
"dam"
,
person
=
"app"
),
ThenChanges
(
True
,
True
,
True
,
True
))
self
.
assertEquals
(
visited
.
cn
,
orig_cn
)
self
.
assertEquals
(
visited
.
email
,
orig_email
)
for
u
in
self
.
users
.
viewkeys
()
-
frozenset
((
"adv"
,
"fd"
,
"dam"
)):
if
"edit_bio"
in
visit_perms
:
self
.
assertVisit
(
WhenPost
(
user
=
u
,
person
=
"adv"
),
ThenForbidden
())
self
.
assertEquals
(
visited
.
bio
,
"Z"
)
self
.
assertVisit
(
WhenPost
(
user
=
"adv"
,
person
=
"adv"
),
ThenChanges
(
False
,
False
,
True
,
False
))
else
:
self
.
assertVisit
(
WhenPost
(
user
=
"fd"
,
person
=
"adv"
),
ThenChanges
(
False
,
True
,
True
,
True
))
self
.
assertEquals
(
visited
.
bio
,
orig_bio
)
self
.
assertVisit
(
WhenPost
(
user
=
"dam"
,
person
=
"adv"
),
ThenChanges
(
False
,
True
,
True
,
True
))
if
self
.
persons
[
visitor
].
is_admin
:
self
.
assertEquals
(
visited
.
fd_comment
,
"Z"
)
for
u
in
self
.
users
.
viewkeys
()
-
frozenset
((
"fd"
,
"dam"
)):
self
.
assertEquals
(
visited
.
status
,
new_status
)
self
.
assertVisit
(
WhenPost
(
user
=
u
,
person
=
"fd"
),
ThenForbidden
())
else
:
self
.
assertVisit
(
WhenPost
(
user
=
"fd"
,
person
=
"fd"
),
ThenChanges
(
False
,
True
,
True
,
True
))
self
.
assertEquals
(
visited
.
fd_comment
,
orig_fd_comment
)
self
.
assertVisit
(
WhenPost
(
user
=
"dam"
,
person
=
"fd"
),
ThenChanges
(
False
,
True
,
True
,
True
))
self
.
assertEquals
(
visited
.
status
,
orig_status
)
for
u
in
self
.
users
.
viewkeys
()
-
frozenset
((
"fd"
,
"dam"
)):
self
.
assertVisit
(
WhenPost
(
user
=
u
,
person
=
"dam"
),
ThenForbidden
())
self
.
assertVisit
(
WhenPost
(
user
=
"fd"
,
person
=
"dam"
),
ThenChanges
(
False
,
True
,
True
,
True
))
self
.
assertVisit
(
WhenPost
(
user
=
"dam"
,
person
=
"dam"
),
ThenChanges
(
False
,
True
,
True
,
True
))
restricted/views.py
View file @
9bc9adf8
...
@@ -174,28 +174,26 @@ class AMProfile(VisitPersonTemplateView):
...
@@ -174,28 +174,26 @@ class AMProfile(VisitPersonTemplateView):
context
=
self
.
get_context_data
(
**
kw
)
context
=
self
.
get_context_data
(
**
kw
)
return
self
.
render_to_response
(
context
)
return
self
.
render_to_response
(
context
)
class
Person
(
VisitPersonTemplateView
):
class
Person
(
VisitPersonTemplateView
):
"""
"""
Edit a person's information
Edit a person's information
"""
"""
template_name
=
"restricted/person.html"
template_name
=
"restricted/person.html"
def
get_person_form
(
self
):
def
check_permissions
(
self
):
perms
=
self
.
visit_perms
.
perms
super
(
Person
,
self
).
check_permissions
()
if
"edit_bio"
not
in
self
.
visit_perms
and
"edit_ldap"
not
in
self
.
visit_perms
:
# Check permissions
if
"edit_bio"
not
in
perms
and
"edit_ldap"
not
in
perms
:
raise
PermissionDenied
raise
PermissionDenied
# Build the form to edit the person
def
get_person_form
(
self
):
includes
=
[]
includes
=
[]
if
"edit_ldap"
in
perms
:
if
"edit_ldap"
in
self
.
visit_
perms
:
includes
.
extend
((
"cn"
,
"mn"
,
"sn"
,
"email"
,
"uid"
))
includes
.
extend
((
"cn"
,
"mn"
,
"sn"
,
"email"
,
"uid"
))
if
self
.
visitor
.
is_admin
:
if
self
.
visitor
.
is_admin
:
includes
.
extend
((
"status"
,
"fd_comment"
,
"expires"
,
"pending"
))
includes
.
extend
((
"status"
,
"fd_comment"
,
"expires"
,
"pending"
))
if
"edit_bio"
in
perms
:
if
"edit_bio"
in
self
.
visit_
perms
:
includes
.
append
(
"bio"
)
includes
.
append
(
"bio"
)
class
PersonForm
(
forms
.
ModelForm
):
class
PersonForm
(
forms
.
ModelForm
):
class
Meta
:
class
Meta
:
model
=
bmodels
.
Person
model
=
bmodels
.
Person
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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