 Permissions, roles, security
==============================


Extra permissions
-----------------

Plonehrm defines three extra permissions. ``plonehrm.viewHrmContent`` as a
special view permission as we want to make sure our senstive personal
information is safe. ``plonehrm.addEmployee`` and ``plonehrm.addWorklocation``
safeguard our two main contenttypes.

  >>> checkPermission = self.portal.portal_membership.checkPermission
  >>> self.portal.permission_settings('plonehrm: View hrm content')
  [{...}]
  >>> self.portal.permission_settings('plonehrm: Add employee')
  [{...}]
  >>> self.portal.permission_settings('plonehrm: Add worklocation')
  [{...}]


Extra roles
-----------

Plonehrm defines two extra roles, all intended for local use.

- HrmManager is mostly the same as the normal Manager, but it is defined as an
  extra role to make it easier to allow people to manage the plonehrm
  application without immediately giving them admin powers in the whole site.

- WorklocationManager is a local role that should be dished out to the manager
  of a worklocation locally, so on the worklocation itself. The goal is to
  give someone local worklocation administration rights. As there might be
  tasks that are restricted to HrmManagers, the worklocation manager should
  not be made owner of the worklocation, as that effectively gives him local
  manager rights.

  >>> data = list(portal.__ac_roles__)
  >>> 'HrmManager' in data
  True
  >>> 'WorklocationManager' in data
  True


Extra workflow for employees
----------------------------

Employees have a new workflow. It is a simple two-state workflow that only
distinguishes between active and non-active employees. This way, ex-employees
can be omitted from the employee listing, but can remain stored in the
system. The workflow doesn't actually do anything with permissions currently.

First some setup code. We add a regular manager and both a hrm manager and a
worklocation manager. Those last two will later on get a local role. And we
add an employee to use that as a regular site member.

  >>> self.loginAsPortalOwner()
  >>> self.portal.portal_membership.addMember('admin', 'secret',
  ...                                         ['Manager'], [])
  >>> self.portal.portal_membership.addMember('hrmmanager', 'secret',
  ...                                         ['Member'], [])
  >>> self.portal.portal_membership.addMember('wlmanager', 'secret',
  ...                                         ['Member'], [])
  >>> self.portal.portal_membership.addMember('employee1', 'secret',
  ...                                         ['Member'], [])
  >>> from Products.CMFCore.utils import getToolByName
  >>> wf_tool = getToolByName(portal, 'portal_workflow')

Managers or other local contributors can add worklocations.

  >>> self.login('admin')
  >>> checkPermission('plonehrm: Add worklocation', self.portal)
  1
  >>> self.portal.invokeFactory('WorkLocation', id='worklocation')
  'worklocation'
  >>> checkPermission('plonehrm: View hrm content', self.portal.worklocation)
  1
  >>> self.portal.worklocation.manage_addLocalRoles('wlmanager',
  ...                                               ('WorklocationManager',))
  >>> self.portal.worklocation.manage_addLocalRoles('hrmmanager',
  ...                                               ('HrmManager',))
  >>> factory = self.portal.worklocation.restrictedTraverse('invokeFactory')
  >>> factory('Employee', id='employee')
  'employee'
  >>> self.portal.worklocation.invokeFactory('Employee', id='employee2')
  'employee2'
  >>> employee = self.portal.worklocation.employee

The initial state of an employee is "active".

  >>> wf_tool.getInfoFor(employee, 'review_state')
  'active'
  >>> wf_tool.doActionFor(employee, 'deactivate')
  >>> wf_tool.getInfoFor(employee, 'review_state')
  'inactive'

If we're anonymous, we cannot yet access the worklocation as the
intranet_folder_workflow allows only members to see the worklocation.

  >>> self.logout()
  >>> self.portal.restrictedTraverse('worklocation')
  Traceback (most recent call last):
  ...
  Unauthorized: You are not allowed to access 'worklocation' in this context

If we log in, the worklocation is visible to us (as we're a member of the
site). The employee inside it is invisible, however

  >>> self.login('employee1')
  >>> checkPermission('plonehrm: View hrm content', self.portal.worklocation)
  1
  >>> self.portal.restrictedTraverse('worklocation')
  <WorkLocation at /plone/worklocation>
  >>> self.portal.restrictedTraverse('worklocation/employee')
  Traceback (most recent call last):
  ...
  Unauthorized: You are not allowed to access 'employee' in this context

If we log in as the worklocation manager we can see both employees.

  >>> self.login('wlmanager')
  >>> checkPermission('plonehrm: View hrm content', self.portal.worklocation)
  1
  >>> self.portal.restrictedTraverse('worklocation/employee')
  <Employee at /plone/worklocation/employee>
  >>> self.portal.restrictedTraverse('worklocation/employee2')
  <Employee at /plone/worklocation/employee2>

We'll activate the employee again.

  >>> self.login('admin')
  >>> wf_tool.doActionFor(employee, 'activate')


Extra workflow for employee modules
-----------------------------------

We don't provide an employee module ourselves, so we'll have to mimic
one. For this, we shall attach the employee module workflow to an
ordinary folder.

  >>> self.login('admin')
  >>> wf_tool.setChainForPortalTypes(['Folder'], 'EmployeeModuleWorkflow')
  >>> employee.invokeFactory('Folder', 'empmod')
  'empmod'

The initial state is that a module is visible for both employees and
worklocation managers, but not for anonymous.

  >>> wf_tool.getInfoFor(employee.empmod, 'review_state')
  'visible_for_employee'

The worklocation manager can see the it and the employee too.

  >>> self.login('wlmanager')
  >>> self.portal.restrictedTraverse('worklocation/employee/empmod')
  <ATFolder at /plone/worklocation/employee/empmod>
  >>> self.login('wlemployee')
  >>> self.portal.restrictedTraverse('worklocation/employee/empmod')
  <ATFolder at /plone/worklocation/employee/empmod>

An anonymous visitor cannot, in this case as it cannot access the
employee. We'll test it with a folder in the site root, then.

  >>> self.login('admin')
  >>> self.portal.invokeFactory('Folder', 'empmod')
  'empmod'
  >>> self.logout()
  >>> self.portal.restrictedTraverse('empmod')
  Traceback (most recent call last):
  ...
  Unauthorized: You are not allowed to access 'empmod' in this context

If we change the workflow state of the employee module to
`visible_for_worklocation_manager`, employees are prevented from
seeing it.

  >>> self.login('admin')
  >>> wf_tool.doActionFor(employee.empmod, 'hide_for_employee')
  >>> self.login('wlemployee')
  >>> self.portal.restrictedTraverse('worklocation/employee/empmod')
  Traceback (most recent call last):
  ...
  Unauthorized: You are not allowed to access 'empmod' in this context

Some employee modules are folderish. The same rules as for editing
should be in effect for adding content. A manager can add things:

  >>> self.login('admin')
  >>> empmod = self.portal.worklocation.employee.empmod
  >>> method = empmod.restrictedTraverse('invokeFactory')

A worklocation manager can also add items:

  >>> self.login('wlmanager')
  >>> empmod = self.portal.restrictedTraverse('worklocation/employee/empmod')
  >>> empmod
  <ATFolder at /plone/worklocation/employee/empmod>
  >>> mtool = getToolByName(self.portal, 'portal_membership')
  >>> checkPermission = mtool.checkPermission
  >>> checkPermission('Add portal content', empmod)
  1
  >>> checkPermission('List folder contents', empmod)
  1
  >>> method = empmod.restrictedTraverse('invokeFactory')

An employee cannot edit the module and he also cannot add items:

  >>> self.login('wlemployee')
  >>> method = empmod.restrictedTraverse('invokeFactory')
  Traceback (most recent call last):
  ...
  Unauthorized: You are not allowed to access 'invokeFactory' in this context
