Commit 9bc9adf8 authored by Enrico Zini's avatar Enrico Zini
Browse files

Refactored Permissions sytem

parent c64e62d0
...@@ -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):
......
This diff is collapsed.
...@@ -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();
...@@ -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):
......
...@@ -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")
......
# 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))
...@@ -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
......
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